Пример #1
0
 public static void Main(string[] args)
 {
     SilkUtility.PrintLogo();
     if (ArgumentEscaper.EscapeAndConcatenate(args).Length == 0)
     {
         SilkUtility.PrintHelp();
         return;
     }
     CommandLineApplication.Execute <Silk>(args);
 }
Пример #2
0
        public static void SetupCtrlCHandler(Action action)
        {
            ctrlCExecuted = false;
            if (ctrlCHandler != null)
            {
                Console.CancelKeyPress -= ctrlCHandler;
            }

            ctrlCHandler = (object sender, ConsoleCancelEventArgs cancelArgs) =>
            {
                if (!ctrlCExecuted)
                {
                    ctrlCExecuted = true;
                    SilkUtility.ReturnStatusMessage("[>] Stopping trace collector..", ConsoleColor.Yellow);
                    action();
                    cancelArgs.Cancel = true;
                }
            };
            Console.CancelKeyPress += ctrlCHandler;
        }
Пример #3
0
        // Print help
        public static void PrintHelp()
        {
            string HelpText = "\n >--~~--> Args? <--~~--<\n\n" +
                              "-h  (--help)          This help menu\n" +
                              "-s  (--silk)          Trivia about Silk\n" +
                              "-t  (--type)          Specify if we are using a Kernel or User collector\n" +
                              "-kk (--kernelkeyword) Valid keywords: Process, Thread, ImageLoad, ProcessCounters, ContextSwitch,\n" +
                              "                      DeferedProcedureCalls, Interrupt, SystemCall, DiskIO, DiskFileIO, DiskIOInit,\n" +
                              "                      Dispatcher, Memory, MemoryHardFaults, VirtualAlloc, VAMap, NetworkTCPIP, Registry,\n" +
                              "                      AdvancedLocalProcedureCalls, SplitIO, Handle, Driver, OS, Profile, Default,\n" +
                              "                      ThreadTime, FileIO, FileIOInit, Verbose, All, IOQueue, ThreadPriority,\n" +
                              "                      ReferenceSet, PMCProfile, NonContainer\n" +
                              "-uk (--userkeyword)   Define a mask of valid keywords, eg 0x2038 -> JitKeyword|InteropKeyword|\n" +
                              "                      LoaderKeyword|NGenKeyword\n" +
                              "-pn (--providername)  User ETW provider name, eg \"Microsoft-Windows-DotNETRuntime\" or its\n" +
                              "                      corresponding GUID eg \"e13c0d23-ccbc-4e12-931b-d9cc2eee27e4\"\n" +
                              "-l  (--level)         Logging level: Always, Critical, Error, Warning, Informational, Verbose\n" +
                              "-ot (--outputtype)    Output type: POST to \"URL\", write to \"file\" or write to \"eventlog\"\n" +
                              "-p  (--path)          Full output file path or URL. Event logs are automatically written to\n" +
                              "                      \"Applications and Services Logs\\SilkETW-Log\"\n" +
                              "-f  (--filter)        Filter types: None, EventName, ProcessID, ProcessName, Opcode\n" +
                              "-fv (--filtervalue)   Filter type capture value, eg \"svchost\" for ProcessName\n" +
                              "-y  (--yara)          Full path to folder containing Yara rules\n" +
                              "-yo (--yaraoptions)   Either record \"All\" events or only \"Matches\"\n\n" +

                              " >--~~--> Usage? <--~~--<\n";

            Console.WriteLine(HelpText);
            SilkUtility.ReturnStatusMessage("# Use a VirtualAlloc Kernel collector, POST results to Elasticsearch", ConsoleColor.Green);
            Console.WriteLine("SilkETW.exe -t kernel -kk VirtualAlloc -ot url -p https://some.elk:9200/valloc/_doc/\n");
            SilkUtility.ReturnStatusMessage("# Use a Process Kernel collector, filter on PID", ConsoleColor.Green);
            Console.WriteLine("SilkETW.exe -t kernel -kk Process -ot url -p https://some.elk:9200/kproc/_doc/ -f ProcessID -fv 11223\n");
            SilkUtility.ReturnStatusMessage("# Use a .Net User collector, specify mask, filter on EventName, write to file", ConsoleColor.Green);
            Console.WriteLine("SilkETW.exe -t user -pn Microsoft-Windows-DotNETRuntime -uk 0x2038 -ot file -p C:\\Some\\Path\\out.json -f EventName -fv Method/LoadVerbose\n");
            SilkUtility.ReturnStatusMessage("# Use a DNS User collector, specify log level, write to file", ConsoleColor.Green);
            Console.WriteLine("SilkETW.exe -t user -pn Microsoft-Windows-DNS-Client -l Always -ot file -p C:\\Some\\Path\\out.json\n");
            SilkUtility.ReturnStatusMessage("# Use an LDAP User collector, perform Yara matching, POST matches to Elasticsearch", ConsoleColor.Green);
            Console.WriteLine("SilkETW.exe -t user -pn Microsoft-Windows-Ldap-Client -ot url -p https://some.elk:9200/ldap/_doc/ -y C:\\Some\\Yara\\Rule\\Folder -yo matches\n");
            SilkUtility.ReturnStatusMessage("# Specify \"Microsoft-Windows-COM-Perf\" by its GUID, write results to the event log", ConsoleColor.Green);
            Console.WriteLine("SilkETW.exe -t user -pn b8d6861b-d20f-4eec-bbae-87e0dd80602b -ot eventlog");
        }
Пример #4
0
        public static int ProcessJSONEventData(String JSONData, OutputType OutputType, String Path, String YaraScan, YaraOptions YaraOptions)
        {
            // Yara options
            if (YaraScan != String.Empty)
            {
                byte[]           JSONByteArray = Encoding.ASCII.GetBytes(JSONData);
                List <YSMatches> Matches       = SilkUtility.YaraInstance.ScanMemory(JSONByteArray, SilkUtility.YaraRules, null, 0);
                SilkUtility.YaraRuleMatches.Clear();
                if (Matches.Count != 0)
                {
                    foreach (YSMatches Match in Matches)
                    {
                        SilkUtility.YaraRuleMatches.Add(Match.Rule.Identifier);
                        lock (ConsoleWriterLock)
                        {
                            SilkUtility.ReturnStatusMessage($"     -> Yara match: {Match.Rule.Identifier}", ConsoleColor.Magenta);
                        }
                    }

                    // Dynamically update the JSON object -> List<String> YaraRuleMatches
                    JObject obj = JObject.Parse(JSONData);
                    ((JArray)obj["YaraMatch"]).Add(SilkUtility.YaraRuleMatches);
                    JSONData = obj.ToString(Newtonsoft.Json.Formatting.None);
                }
            }

            if (YaraOptions == YaraOptions.All || YaraOptions == YaraOptions.None || (YaraScan != String.Empty && SilkUtility.YaraRuleMatches.Count > 0))
            {
                //--[Return Codes]
                // 0 == OK
                // 1 == File write failed
                // 2 == URL POST request failed
                // 3 == Eventlog write failed
                //--

                // Process JSON
                if (OutputType == OutputType.file)
                {
                    try
                    {
                        if (!File.Exists(Path))
                        {
                            File.WriteAllText(Path, (JSONData + Environment.NewLine));
                        }
                        else
                        {
                            File.AppendAllText(Path, (JSONData + Environment.NewLine));
                        }

                        return(0);
                    }
                    catch
                    {
                        return(1);
                    }
                }
                else if (OutputType == OutputType.url)
                {
                    try
                    {
                        string         responseFromServer = string.Empty;
                        HttpWebRequest webRequest         = (HttpWebRequest)WebRequest.Create(Path);
                        webRequest.Timeout     = 10000; // 10 second timeout
                        webRequest.Method      = "POST";
                        webRequest.ContentType = "application/json";
                        webRequest.Accept      = "application/json";
                        using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                        {
                            streamWriter.Write(JSONData);
                            streamWriter.Flush();
                            streamWriter.Close();
                        }
                        var httpResponse = (HttpWebResponse)webRequest.GetResponse();
                        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                        {
                            var result = streamReader.ReadToEnd();
                        }

                        return(0);
                    }
                    catch
                    {
                        return(2);
                    }
                }
                else
                {
                    Boolean WriteEvent = WriteEventLogEntry(JSONData, EventLogEntryType.Information, EventIds.Event, Path);
                    if (WriteEvent)
                    {
                        return(0);
                    }
                    else
                    {
                        return(3);
                    }
                }
            }
            else
            {
                return(0);
            }
        }
Пример #5
0
        public static void StartTrace(CollectorType CollectorType, ulong TraceKeywords, OutputType OutputType, String Path, FilterOption FilterOption, Object FilterValue, String YaraScan, YaraOptions YaraOptions, String ProviderName = "", UserTraceEventLevel UserTraceEventLevel = UserTraceEventLevel.Informational)
        {
            // Is elevated?
            if (TraceEventSession.IsElevated() != true)
            {
                SilkUtility.ReturnStatusMessage("[!] The collector must be run as Administrator..", ConsoleColor.Red);
                return;
            }

            // Print status
            SilkUtility.ReturnStatusMessage("[>] Starting trace collector (Ctrl-c to stop)..", ConsoleColor.Yellow);
            SilkUtility.ReturnStatusMessage("[?] Events captured: 0", ConsoleColor.Green); // We will update this dynamically

            // The kernel collector has naming requirements
            if (CollectorType == CollectorType.Kernel)
            {
                SilkUtility.EventParseSessionName = KernelTraceEventParser.KernelSessionName;
            }
            else
            {
                // We add a GUID in case of concurrent SilkETW execution
                String RandId = Guid.NewGuid().ToString();
                SilkUtility.EventParseSessionName = ("SilkETWUserCollector_" + RandId);
            }

            // Create trace session
            using (var TraceSession = new TraceEventSession(SilkUtility.EventParseSessionName))
            {
                // The collector cannot survive process termination (safeguard)
                TraceSession.StopOnDispose = true;

                // Create event source
                using (var EventSource = new ETWTraceEventSource(SilkUtility.EventParseSessionName, TraceEventSourceType.Session))
                {
                    // Ctrl-c callback handler
                    SilkUtility.SetupCtrlCHandler(() =>
                    {
                        TerminateCollector();
                    });

                    // A DynamicTraceEventParser can understand how to read the embedded manifests that occur in the dataStream
                    var EventParser = new DynamicTraceEventParser(EventSource);

                    // Loop events as they arrive
                    EventParser.All += delegate(TraceEvent data)
                    {
                        // It's a bit ugly but ... ¯\_(ツ)_/¯
                        if (FilterOption != FilterOption.None)
                        {
                            if (FilterOption == FilterOption.Opcode && (byte)data.Opcode != (byte)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else if (FilterOption == FilterOption.ProcessID && data.ProcessID != (UInt32)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else if (FilterOption == FilterOption.ProcessName && data.ProcessName != (String)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else if (FilterOption == FilterOption.EventName && data.EventName != (String)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else
                            {
                                SilkUtility.ProcessEventData = true;
                            }
                        }
                        else
                        {
                            SilkUtility.ProcessEventData = true;
                        }

                        // Only process/serialize events if they match our filter
                        if (SilkUtility.ProcessEventData)
                        {
                            // Display running event count
                            SilkUtility.RunningEventCount += 1;
                            SilkUtility.UpdateEventCount("[?] Events captured: " + SilkUtility.RunningEventCount);

                            var eRecord = new EventRecordStruct
                            {
                                ProviderGuid    = data.ProviderGuid,
                                YaraMatch       = new List <String>(),
                                ProviderName    = data.ProviderName,
                                EventName       = data.EventName,
                                Opcode          = data.Opcode,
                                OpcodeName      = data.OpcodeName,
                                TimeStamp       = data.TimeStamp,
                                ThreadID        = data.ThreadID,
                                ProcessID       = data.ProcessID,
                                ProcessName     = data.ProcessName,
                                PointerSize     = data.PointerSize,
                                EventDataLength = data.EventDataLength
                            };
                            var EventProperties = new Hashtable();

                            // Try to parse event XML
                            try
                            {
                                StringReader  XmlStringContent   = new StringReader(data.ToString());
                                XmlTextReader EventElementReader = new XmlTextReader(XmlStringContent);
                                while (EventElementReader.Read())
                                {
                                    for (int AttribIndex = 0; AttribIndex < EventElementReader.AttributeCount; AttribIndex++)
                                    {
                                        EventElementReader.MoveToAttribute(AttribIndex);
                                        EventProperties.Add(EventElementReader.Name, EventElementReader.Value);
                                    }
                                }
                            }
                            catch
                            {
                                // For debugging (?), never seen this fail
                                EventProperties.Add("XmlEventParsing", "false");
                            }
                            eRecord.XmlEventData = EventProperties;

                            // Serialize to JSON
                            String JSONEventData = Newtonsoft.Json.JsonConvert.SerializeObject(eRecord);
                            int    ProcessResult = SilkUtility.ProcessJSONEventData(JSONEventData, OutputType, Path, YaraScan, YaraOptions);

                            // Verify that we processed the result successfully
                            if (ProcessResult != 0)
                            {
                                if (ProcessResult == 1)
                                {
                                    SilkUtility.ReturnStatusMessage("[!] The collector failed to write to file", ConsoleColor.Red);
                                }
                                else
                                {
                                    SilkUtility.ReturnStatusMessage("[!] The collector failed to POST the result", ConsoleColor.Red);
                                }

                                // Shut down the collector
                                TerminateCollector();
                            }
                        }
                    };

                    // Specify the providers details
                    if (CollectorType == CollectorType.Kernel)
                    {
                        TraceSession.EnableKernelProvider((KernelTraceEventParser.Keywords)TraceKeywords);
                    }
                    else
                    {
                        // Note that the collector doesn't know if you specified a wrong provider name,
                        // the only tell is that you won't get any events ;)
                        TraceSession.EnableProvider(ProviderName, (TraceEventLevel)UserTraceEventLevel, TraceKeywords);
                    }

                    // Continuously process all new events in the data source
                    EventSource.Process();

                    // Helper to clean up colloector
                    void TerminateCollector()
                    {
                        EventSource.StopProcessing();
                        TraceSession?.Stop();
                        Console.CursorVisible = true;
                        SilkUtility.ReturnStatusMessage("[+] Collector terminated", ConsoleColor.Green);
                    }
                }
            }
        }
Пример #6
0
        private void OnExecute()
        {
            // Print custom help
            if (Help)
            {
                SilkUtility.PrintHelp();
                return;
            }

            // Print trivia
            if (Trivia)
            {
                SilkUtility.PrintTrivia();
                return;
            }

            // What type of collector are we creating?
            if (CollectorType == CollectorType.None)
            {
                SilkUtility.ReturnStatusMessage("[!] Select valid collector type (-t|--type)", ConsoleColor.Red);
                return;
            }
            else if (CollectorType == CollectorType.Kernel)
            {
                if (KernelKeywords == KernelKeywords.None)
                {
                    SilkUtility.ReturnStatusMessage("[!] Select valid Kernel keyword (-kk|--kernelkeyword)", ConsoleColor.Red);
                    return;
                }
            }
            else if (CollectorType == CollectorType.User)
            {
                if (String.IsNullOrEmpty(ProviderName))
                {
                    SilkUtility.ReturnStatusMessage("[!] Specify valid provider name (-pn|--providername)", ConsoleColor.Red);
                    return;
                }

                // Check and convert UserKeywords to ulong
                if (String.IsNullOrEmpty(UserKeywords))
                {
                    SilkUtility.ReturnStatusMessage("[!] Specify valid keywords mask (-uk|--userkeyword)", ConsoleColor.Red);
                    return;
                }
                else
                {
                    try
                    {
                        if (UserKeywords.StartsWith("0x"))
                        {
                            SilkUtility.UlongUserKeywords = Convert.ToUInt64(UserKeywords, 16);
                        }
                        else
                        {
                            SilkUtility.UlongUserKeywords = Convert.ToUInt64(UserKeywords);
                        }
                    }
                    catch
                    {
                        SilkUtility.ReturnStatusMessage("[!] Specify valid keywords mask (-uk|--userkeyword)", ConsoleColor.Red);
                        return;
                    }
                }
            }

            // Validate output parameters
            if (OutputType == OutputType.None)
            {
                SilkUtility.ReturnStatusMessage("[!] Select valid output type (-ot|--outputtype)", ConsoleColor.Red);
                return;
            }
            else
            {
                if (OutputType == OutputType.file)
                {
                    if (String.IsNullOrEmpty(Path))
                    {
                        SilkUtility.ReturnStatusMessage("[!] Specify valid output file (-p|--path)", ConsoleColor.Red);
                        return;
                    }
                    else
                    {
                        try
                        {
                            FileAttributes CheckAttrib = File.GetAttributes(Path);
                            if (CheckAttrib.HasFlag(FileAttributes.Directory))
                            {
                                SilkUtility.ReturnStatusMessage("[!] Specify an output filepath not a directory (-p|--path)", ConsoleColor.Red);
                                return;
                            }
                        }
                        catch { }
                        if (!(Directory.Exists(System.IO.Path.GetDirectoryName(Path))))
                        {
                            SilkUtility.ReturnStatusMessage("[!] Invalid path specified (-p|--path)", ConsoleColor.Red);
                            return;
                        }
                        else
                        {
                            if (!(SilkUtility.DirectoryHasPermission(System.IO.Path.GetDirectoryName(Path), System.Security.AccessControl.FileSystemRights.Write)))
                            {
                                SilkUtility.ReturnStatusMessage("[!] No write access to output path (-p|--path)", ConsoleColor.Red);
                                return;
                            }
                        }
                    }
                }
                else
                {
                    if (String.IsNullOrEmpty(Path))
                    {
                        SilkUtility.ReturnStatusMessage("[!] Specify valid URL (-p|--path)", ConsoleColor.Red);
                        return;
                    }
                    else
                    {
                        Uri  uriResult;
                        bool UrlResult = Uri.TryCreate(Path, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
                        if (!UrlResult)
                        {
                            SilkUtility.ReturnStatusMessage("[!] Invalid URL specified (-p|--path)", ConsoleColor.Red);
                            return;
                        }
                    }
                }
            }

            // Validate filter options
            // None, EventName, ProcessID, ProcessName, Opcode
            if (FilterOption != FilterOption.None)
            {
                if (String.IsNullOrEmpty(FilterValue))
                {
                    SilkUtility.ReturnStatusMessage("[!] Specify a valid filter value (-fv|--filtervalue) in conjunction with -f", ConsoleColor.Red);
                    return;
                }
                if (FilterOption == FilterOption.ProcessID)
                {
                    try
                    {
                        SilkUtility.FilterValueObject = Convert.ToUInt32(FilterValue);
                    }
                    catch
                    {
                        SilkUtility.ReturnStatusMessage("[!] Specify a valid ProcessID", ConsoleColor.Red);
                        return;
                    }
                }
                else if (FilterOption == FilterOption.Opcode)
                {
                    try
                    {
                        SilkUtility.FilterValueObject = byte.Parse(FilterValue);
                        if ((byte)SilkUtility.FilterValueObject > 9)
                        {
                            SilkUtility.ReturnStatusMessage("[!] Opcode outside valid range (0-9)", ConsoleColor.Red);
                            return;
                        }
                    }
                    catch
                    {
                        SilkUtility.ReturnStatusMessage("[!] Specify a valid Opcode", ConsoleColor.Red);
                        return;
                    }
                }
                else
                {
                    SilkUtility.FilterValueObject = FilterValue;
                }
            }

            // Validate Yara folder path
            if (YaraScan != String.Empty)
            {
                try
                {
                    FileAttributes CheckAttrib = File.GetAttributes(YaraScan);
                    if (!(CheckAttrib.HasFlag(FileAttributes.Directory)))
                    {
                        SilkUtility.ReturnStatusMessage("[!] Specified path is not a folder (-y|--yara)", ConsoleColor.Red);
                        return;
                    }
                    else
                    {
                        List <string> YaraRuleCollection = Directory.GetFiles(YaraScan, "*.yar", SearchOption.AllDirectories).ToList();
                        if (YaraRuleCollection.Count == 0)
                        {
                            SilkUtility.ReturnStatusMessage("[!] Yara folder path does not contain any *.yar files (-y|--yara)", ConsoleColor.Red);
                            return;
                        }
                        else
                        {
                            // We already initialize yara for performace,
                            // new rules can not be added at runtime.
                            SilkUtility.YaraInstance = new YSInstance();
                            SilkUtility.YaraContext  = new YSContext();
                            SilkUtility.YaraCompiler = SilkUtility.YaraInstance.CompileFromFiles(YaraRuleCollection, null);
                            SilkUtility.YaraRules    = SilkUtility.YaraCompiler.GetRules();
                            YSReport YaraReport = SilkUtility.YaraCompiler.GetErrors();

                            if (!(YaraReport.IsEmpty()))
                            {
                                SilkUtility.ReturnStatusMessage("[!] The following yara errors were detected (-y|--yara)", ConsoleColor.Red);

                                Dictionary <string, List <string> > Errors = YaraReport.Dump();
                                foreach (KeyValuePair <string, List <string> > Error in Errors)
                                {
                                    SilkUtility.ReturnStatusMessage("==> " + Error.Key, ConsoleColor.Yellow);
                                    foreach (String ErrorMsg in Error.Value)
                                    {
                                        SilkUtility.ReturnStatusMessage("    + " + ErrorMsg, ConsoleColor.Yellow);
                                    }
                                }
                                return;
                            }
                        }
                    }
                }
                catch
                {
                    SilkUtility.ReturnStatusMessage("[!] Specify a valid yara rule folder path (-y|--yara)", ConsoleColor.Red);
                    return;
                }

                if (YaraOptions == YaraOptions.None)
                {
                    SilkUtility.ReturnStatusMessage("[!] Specify a valid yara option (-yo|--yaraoptions)", ConsoleColor.Red);
                    return;
                }
            }

            // We passed all collector parameter checks
            SilkUtility.ReturnStatusMessage("[+] Collector parameter validation success..", ConsoleColor.Green);

            // Launch the collector
            if (CollectorType == CollectorType.Kernel)
            {
                ETWCollector.StartTrace(CollectorType, (ulong)KernelKeywords, OutputType, Path, FilterOption, SilkUtility.FilterValueObject, YaraScan, YaraOptions);
            }
            else
            {
                ETWCollector.StartTrace(CollectorType, SilkUtility.UlongUserKeywords, OutputType, Path, FilterOption, SilkUtility.FilterValueObject, YaraScan, YaraOptions, ProviderName, UserTraceEventLevel);
            }
        }