Skip to content

Commit

Permalink
Merge pull request #1 from H4NM/dev
Browse files Browse the repository at this point in the history
Update to 1.1 🚀
  • Loading branch information
H4NM authored Oct 7, 2024
2 parents 4b72261 + c8407dd commit e4983f5
Show file tree
Hide file tree
Showing 27 changed files with 539 additions and 299 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Hannes
Copyright (c) 2024 Hannes Michel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ However, there are some downsides:
- Can start and monitor an executable.
- Can monitor an already running process.
- Can monitor additional related processes based on executable names.
- Executables can be run as other users and in elevated and unelevated states.
- Creates a full packet capture .pcap file per process.
- Records TCPIP activities made by a processes, netflow style.
- Records DNS requests and responses made and retrieved by applications.
Expand Down Expand Up @@ -76,9 +77,13 @@ There are other tools that can compliment your quest of application network anal

### Limitations
- **DNS**: In ETW, `Microsoft-Windows-DNS-Client` only logs A and AAAA queries, neglecting other DNS query types such as PTR, TXT, MX, SOA etc. It does capture CNAME and it's respective adresses, which are part of the DNS response. However, with the FPC the requests are captured either way, just not portrayed as in registered DNS traffic by the application.
- **Execution integrity**: It's currently not possible to delegate the privilege of executing applications in an elevated state to other users, meaning that if you want to run the application elevated you need to be signed in as the user with administrator rights.
Furthermore, since WhoYouCalling requires elevated privileges to run (*ETW + FPC*), spawned processes naturally inherits the security token making them also posess the same integrity level - and .NET api does not work too well with creating less privileged processes from an already elevated state.
The best and most reliable approach was to duplicate the low privileged token of the desktop shell in an interactive logon (explorer.exe).
However, there may be use cases in which WhoYouCalling is executed via a remote management tool like PowerShell, SSH or PsExec, where there is no instance of a desktop shell, in these case you need to provide a username and password of a user that may execute it.

### Dependencies
This project has been tested and works with .NET 8 with two external libraries for capturing ETW activity and network packets:
This project has been tested and works with .NET 8 with two nuget packages, and drivers for capturing network packets:
- FPC:
- [SharpCap](https://github.com/dotpcap/sharppcap)
- [Npcap](https://npcap.com/#download)
Expand Down Expand Up @@ -121,7 +126,6 @@ bin\Release\net8.0\win-x64\WhoYouCalling.exe [arguments]...
### To Do:
- Refactor. Lots and lots to refactor and make more tidy :)
- Add wireshark filter per domain name as their resolved IP addresses can be converted
- Add privileged execution option to spawn the process as administrator
- Add requirement of npcap drivers if pcap interface specified. It would be nice if the drivers are not a requirement when you're specifying `--nopcap` flag.

### Nice to have
Expand Down
2 changes: 1 addition & 1 deletion WhoYouCalling.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x64;x86</Platforms>
<FileVersion>1.0</FileVersion>
<FileVersion>1.1</FileVersion>
<ApplicationManifest>WhoYouCalling\app.manifest</ApplicationManifest>
</PropertyGroup>

Expand Down
46 changes: 46 additions & 0 deletions WhoYouCalling/Constants/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

namespace WhoYouCalling
{
static class Constants
{
public const uint QueryInformation = 0x00000400;
public const uint LogonFlags = 0;
public const uint CreationFlags = 0;

public const Int32 ImpersonationSecurity = 2;
public const Int32 TokenDuplicate = 2;
public const Int32 TokenQuery = 8;
public const Int32 TokenAssignPrimary = 1;
public const Int32 TokenAdjustDefault = 0x80;
public const Int32 TokenAdjustSessionID= 0x100;

public const Int32 PacketCaptureTimeoutMilliseconds = 1000;

public const Int32 ETWSubscriptionTimingTime = 3000;

public const Int32 CombinedFilterProcessID = 0;


// File names
//// Root folder
public const string RootFolderEntirePcapFileName = "Full network packet capture.pcap";
public const string RootFolderAllProcessesFilteredPcapFileName = "All processes network packets.pcap";
public const string RootFolderDFLFilterFileName = "All processes wireshark filter.txt";
public const string RootFolderBPFFilterFileName = "All processes BPF-filter.txt";
public const string RootFolderETWHistoryFileName = "ETW history.txt";
public const string RootFolderJSONProcessDetailsFileName = "Process details.json";
public const string RootFolderJSONDNSResponseFileName = "DNS responses.json";

//// Per Process
public const string ProcessFolderPcapFileName = "Network packets.pcap";
public const string ProcessFolderBPFFilterFileName = "BPF-filter.txt";
public const string ProcessFolderDFLFilterFileName = "Wireshark filter.txt";
public const string ProcessFolderDNSQueriesFileName = "DNS queries.txt";
public const string ProcessFolderIPv4TCPEndpoints = "IPv4 TCP Endpoints.txt";
public const string ProcessFolderIPv6TCPEndpoints = "IPv6 TCP Endpoints.txt";
public const string ProcessFolderIPv4UDPEndpoints = "IPv4 UDP Endpoints.txt";
public const string ProcessFolderIPv6UDPEndpoints = "IPv6 UDP Endpoints.txt";
public const string ProcessFolderIPv4LocalhostEndpoints = "Localhost Endpoints.txt";
public const string ProcessFolderIPv6LocalhostEndpoints = "Localhost Endpoints IPv6.txt";
}
}
14 changes: 10 additions & 4 deletions WhoYouCalling/ETW/DNSClientListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
using Microsoft.Diagnostics.Tracing.Session;
using WhoYouCalling.Network.DNS;
using WhoYouCalling.Utilities;
using WhoYouCalling.WhoYouCalling.Network;
using WhoYouCalling.Network;

namespace WhoYouCalling.ETW
{
internal class DNSClientListener : Listener
{

public DNSClientListener()
{
SourceName = "DNS";
}

public void Listen()
{
using (_session = new TraceEventSession("WhoYouCallingDNSClientSession"))
Expand Down Expand Up @@ -35,7 +41,7 @@ private void DnsClientEvent(TraceEvent data)
ConsoleOutput.Print($"Attempted to parse retrieved DNS Query type. Failed to parse it", PrintType.Debug);
queryTypeCode = 999999; // Non-existing DNS type value. Is later looked up
}
string dnsRecordTypeCodeName = DnsTypeLookup.GetName(queryTypeCode); // Retrieve the DNS type code name
string dnsRecordTypeCodeName = DnsCodeLookup.GetDnsTypeName(queryTypeCode); // Retrieve the DNS type code name

DNSQuery dnsQuery = new DNSQuery
{
Expand Down Expand Up @@ -89,8 +95,8 @@ private void DnsClientEvent(TraceEvent data)
queryTypeCode = 999999; // Non-existing DNS type value. Is later looked up
}

string dnsRecordTypeCodeName = DnsTypeLookup.GetName(queryTypeCode); // Retrieve the DNS type code name
string dnsResponseStatusCodeName = DnsStatusLookup.GetName(queryStatusCode); // Retrieve the DNS response status code name
string dnsRecordTypeCodeName = DnsCodeLookup.GetDnsTypeName(queryTypeCode); // Retrieve the DNS type code name
string dnsResponseStatusCodeName = DnsCodeLookup.GetDnsStatusName(queryStatusCode); // Retrieve the DNS response status code name

DNSResponse dnsResponseQuery = new DNSResponse
{
Expand Down
7 changes: 6 additions & 1 deletion WhoYouCalling/ETW/KernelListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ namespace WhoYouCalling.ETW
{
internal class KernelListener : Listener
{
public KernelListener()
{
SourceName = "Kernel";
}

public void Listen()
{
using (_session = new TraceEventSession(KernelTraceEventParser.KernelSessionName)) //KernelTraceEventParser
Expand Down Expand Up @@ -119,7 +124,7 @@ private void childProcessStarted(ProcessTraceData data)
execObject: data.ImageFileName,
execPID: data.ProcessID,
parentExecPID: data.ParentID);
if (Program.TrackChildProcesses)
if (Program.TrackChildProcesses())
{
Program.AddChildPID(data.ProcessID);
Program.InstantiateProcessVariables(pid: data.ProcessID, executable: data.ImageFileName);
Expand Down
1 change: 1 addition & 0 deletions WhoYouCalling/ETW/Listener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal class Listener
protected int _trackedProcessId = 0;
protected string _mainExecutableFileName = "";
protected TraceEventSession _session;
public string SourceName = "";

public bool IsAMonitoredProcess(int pid)
{
Expand Down
50 changes: 50 additions & 0 deletions WhoYouCalling/Enums/DnsStatusType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

namespace WhoYouCalling.Network.DNS
{
public enum DnsStatusType : int
{
// Official DNS standard types
NoError = 0,
FormErr = 1,
ServFail = 2,
NXDomain = 3,
NotImp = 4,
Refused = 5,
YXDomain = 6,
YXRRSet = 7,
NXRRSet = 8,
NotAuth = 9,
NotZone = 10,
BADVERS = 16,
BADKEY = 17,
BADTIME = 18,
BADMODE = 19,
BADNAME = 20,
BADALG = 21,
BADTRUNC = 22,
BADCOOKIE = 23,

// Custom Windows types
InvalidParameter = 87,
DnsServerUnableToInterpretFormat = 9001,
DnsServerFailure = 9002,
DnsNameDoesNotExist = 9003,
DnsRequestNotSupportedByNameServer = 9004,
DnsOperationRefused = 9005,
DnsNameThatOughtNotExistDoesExist = 9006,
DnsRRSetThatOughtNotExistDoesExist = 9007,
DnsRRSetThatOughtToExistDoesNotExist = 9008,
DnsServerNotAuthoritativeForZone = 9009,
DnsNameInUpdateOrPrereqIsNotInZone = 9010,
DnsSignatureFailedToVerify = 9016,
DnsBadKey = 9017,
DnsSignatureValidityExpired = 9018,
NoRecordsFoundForGivenDnsQuery = 9501,
BadDnsPacket = 9502,
NoDnsPacket = 9503,
UnsecuredDnsPacket = 9505,

// Custom value for non-existent DNS status
NA = 999999
}
}
57 changes: 57 additions & 0 deletions WhoYouCalling/Enums/DnsType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

namespace WhoYouCalling.Network.DNS
{
public enum DnsType : int
{
A = 1, // Address record
NS = 2, // Name server record
CNAME = 5, // Canonical name record
SOA = 6, // Start of authority record
PTR = 12, // Pointer record (reverse DNS)
MX = 15, // Mail exchange record
TXT = 16, // Text record
AAAA = 28, // IPv6 address record
SRV = 33, // Service locator
ANY = 255, // Any type (wildcard)
RP = 17, // Responsible person
AFSDB = 18, // AFS database record
LOC = 29, // Location record
NAPTR = 35, // Naming authority pointer
KX = 36, // Key exchange
CERT = 37, // Certificate record
DNAME = 39, // Delegation name
OPT = 41, // Option record
APL = 42, // Address prefix list
DS = 43, // Delegation signer
SSHFP = 44, // SSH fingerprint
IPSECKEY = 45, // IPSEC key
RRSIG = 46, // Resource record signature
NSEC = 47, // Next secure record
DNSKEY = 48, // DNS key
DHCID = 49, // DHCP identifier
NSEC3 = 50, // Next secure record version 3
NSEC3PARAM = 51, // NSEC3 parameters
TLSA = 52, // TLSA record
SMIMEA = 53, // S/MIME cert association
HIP = 55, // Host identity protocol
CDS = 59, // Child DS
CDNSKEY = 60, // Child DNSKEY
OPENPGPKEY = 61, // OpenPGP key record
CSYNC = 62, // Child-to-parent synchronization
ZONEMD = 63, // Message digest for DNS zone
SVCB = 64, // Service binding
HTTPS = 65, // HTTPS binding
TKEY = 249, // Transaction key
TSIG = 250, // Transaction signature
IXFR = 251, // Incremental zone transfer
AXFR = 252, // Authoritative zone transfer
URI = 256, // URI record
CAA = 257, // Certification authority authorization
AVC = 258, // Application visibility and control
AMTRELAY = 260, // Automatic multicast tunneling relay
TA = 32768, // DNSSEC Trust Authorities
DLV = 32769, // DNSSEC Lookaside Validation

NA = 999999 // Custom Non-existent DNS Type Value
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WhoYouCalling.Utilities

namespace WhoYouCalling
{
public enum PrintType
{
Expand Down
23 changes: 23 additions & 0 deletions WhoYouCalling/Network/DNS/DnsCodeLookup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

namespace WhoYouCalling.Network.DNS
{
public static class DnsCodeLookup
{
public static string GetDnsStatusName(int statusCode)
{
if (Enum.IsDefined(typeof(DnsStatusType), statusCode))
{
return ((DnsStatusType)statusCode).ToString();
}
return DnsStatusType.NA.ToString();
}
public static string GetDnsTypeName(int statusCode)
{
if (Enum.IsDefined(typeof(DnsType), statusCode))
{
return ((DnsType)statusCode).ToString();
}
return DnsType.NA.ToString();
}
}
}
63 changes: 0 additions & 63 deletions WhoYouCalling/Network/DNS/DnsStatusLookup.cs

This file was deleted.

Loading

0 comments on commit e4983f5

Please sign in to comment.