mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-20 20:37:27 +01:00
c7f7bc2fc0
We now use ints, and hopefully this means we don't have as much obvious stuff in the binaries! ``` $ # Before: $ strings metsrv.x86.dll | grep core_ | wc -l 46 $ # After: $ strings metsrv.x86.dll | grep core_ | wc -l 0 ``` Big win, and it's even bigger for the likes of stdapi. Had to fix a bunch of other stuff along the way, including a subtle issue with the Powershell Meterp bindings.
460 lines
15 KiB
C#
Executable File
460 lines
15 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.Management.Automation.Host;
|
|
using System.Management.Automation.Runspaces;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace MSF.Powershell
|
|
{
|
|
public class Runner : IDisposable
|
|
{
|
|
// We use a dictionary of runners based on ID, this means that we can maintain
|
|
// separate sessions if we want to.
|
|
private static Dictionary<string, Runner> _runners;
|
|
private InitialSessionState _state;
|
|
private CustomPSHost _host = null;
|
|
private Runspace _runspace = null;
|
|
private string _id;
|
|
|
|
static Runner()
|
|
{
|
|
System.Diagnostics.Debug.Write("[PSH RUNNER] Static constructor called");
|
|
_runners = new Dictionary<string, Runner>();
|
|
}
|
|
|
|
internal static void Channelise(string id, Int64 channelWriter, Int64 context)
|
|
{
|
|
var runner = Get(id);
|
|
System.Diagnostics.Debug.Write(string.Format("[PSH RUNNER] Channelising {0} with CW 0x{1:X} - CTX 0x{2:X}", id, channelWriter, context));
|
|
runner._host.UserInterface.Channelise(channelWriter, context);
|
|
}
|
|
|
|
internal static void Unchannelise(string id)
|
|
{
|
|
var runner = Get(id);
|
|
System.Diagnostics.Debug.Write(string.Format("[PSH RUNNER] Unchannelising {0}", id));
|
|
runner._host.UserInterface.Unchannelise();
|
|
}
|
|
|
|
internal static string Execute(string id, string ps)
|
|
{
|
|
System.Diagnostics.Debug.Write(string.Format("[PSH RUNNER] Executing command on session {0}", id));
|
|
if (!_runners.ContainsKey(id))
|
|
{
|
|
_runners.Add(id, new Runner(id));
|
|
}
|
|
var runner = _runners[id];
|
|
return runner.Execute(ps);
|
|
}
|
|
|
|
internal static Runner Get(string id)
|
|
{
|
|
if (!_runners.ContainsKey(id))
|
|
{
|
|
_runners.Add(id, new Runner(id));
|
|
}
|
|
return _runners[id];
|
|
}
|
|
|
|
internal static void Remove(string id)
|
|
{
|
|
if (_runners.ContainsKey(id))
|
|
{
|
|
_runners[id].Dispose();
|
|
_runners.Remove(id);
|
|
}
|
|
}
|
|
|
|
internal Runner(string id)
|
|
{
|
|
_id = id;
|
|
_state = InitialSessionState.CreateDefault();
|
|
_state.AuthorizationManager = null;
|
|
|
|
_host = new CustomPSHost();
|
|
|
|
_runspace = RunspaceFactory.CreateRunspace(_host, _state);
|
|
_runspace.Open();
|
|
|
|
// add support straight up for the existing scripts
|
|
foreach(var script in Scripts.GetAllScripts())
|
|
{
|
|
Execute(script);
|
|
}
|
|
}
|
|
|
|
private string InvokePipline(string ps)
|
|
{
|
|
ps = "IEX ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(\"" + Convert.ToBase64String(Encoding.UTF8.GetBytes(ps), Base64FormattingOptions.None) + "\")))";
|
|
System.Diagnostics.Debug.Write(string.Format("[PSH RUNNER] Executing PS directly: {0}", ps));
|
|
using (Pipeline pipeline = _runspace.CreatePipeline())
|
|
{
|
|
pipeline.Commands.AddScript(ps);
|
|
pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
|
|
pipeline.Commands.Add("out-default");
|
|
|
|
pipeline.Invoke();
|
|
}
|
|
|
|
return _host.GetAndFlushOutput();
|
|
}
|
|
|
|
private void ThreadInvokePipeline(object psObj)
|
|
{
|
|
// Sneak a prompt string in at the end.
|
|
var ps = psObj.ToString();
|
|
ps = "IEX ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(\"" + Convert.ToBase64String(Encoding.UTF8.GetBytes(ps), Base64FormattingOptions.None) + "\")))";
|
|
System.Diagnostics.Debug.Write(string.Format("[PSH RUNNER] Executing PS on thread: {0}", ps));
|
|
using (Pipeline pipeline = _runspace.CreatePipeline())
|
|
{
|
|
pipeline.Commands.AddScript(ps);
|
|
pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
|
|
pipeline.Commands.Add("out-default");
|
|
|
|
pipeline.Invoke();
|
|
System.Diagnostics.Debug.Write(string.Format("[PSH RUNNER] Executed PS on thread. Flushing"));
|
|
_host.GetAndFlushOutput();
|
|
_host.UserInterface.WriteRaw("PS > ");
|
|
}
|
|
}
|
|
|
|
internal string Execute(string ps)
|
|
{
|
|
if (_host.UserInterface.IsChannelised)
|
|
{
|
|
var t = new Thread(new ParameterizedThreadStart(ThreadInvokePipeline));
|
|
t.Start(ps);
|
|
return string.Empty;
|
|
}
|
|
|
|
return InvokePipline(ps);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_runspace != null)
|
|
{
|
|
_runspace.Close();
|
|
_runspace.Dispose();
|
|
}
|
|
}
|
|
|
|
private class CustomPSHost : PSHost
|
|
{
|
|
private Guid _hostId;
|
|
private CustomPSHostUserInterface _ui = null;
|
|
|
|
public CustomPSHostUserInterface UserInterface
|
|
{
|
|
get { return _ui; }
|
|
}
|
|
|
|
public CustomPSHost()
|
|
{
|
|
_hostId = Guid.NewGuid();
|
|
_ui = new CustomPSHostUserInterface();
|
|
}
|
|
|
|
public string GetAndFlushOutput()
|
|
{
|
|
var output = _ui.ToString();
|
|
_ui.Clear();
|
|
System.Diagnostics.Debug.Write(string.Format("Output: {0}", output));
|
|
return output;
|
|
}
|
|
|
|
public override System.Globalization.CultureInfo CurrentCulture
|
|
{
|
|
get { return System.Threading.Thread.CurrentThread.CurrentCulture; }
|
|
}
|
|
|
|
public override System.Globalization.CultureInfo CurrentUICulture
|
|
{
|
|
get { return System.Threading.Thread.CurrentThread.CurrentUICulture; }
|
|
}
|
|
|
|
public override void EnterNestedPrompt()
|
|
{
|
|
}
|
|
|
|
public override void ExitNestedPrompt()
|
|
{
|
|
}
|
|
|
|
public override Guid InstanceId
|
|
{
|
|
get { return _hostId; }
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return "MSFConsole"; }
|
|
}
|
|
|
|
public override void NotifyBeginApplication()
|
|
{
|
|
}
|
|
|
|
public override void NotifyEndApplication()
|
|
{
|
|
}
|
|
|
|
public override void SetShouldExit(int exitCode)
|
|
{
|
|
}
|
|
|
|
public override PSHostUserInterface UI
|
|
{
|
|
get { return _ui; }
|
|
}
|
|
|
|
public override Version Version
|
|
{
|
|
get { return new Version(0, 1); }
|
|
}
|
|
}
|
|
|
|
private class CustomPSHostUserInterface : PSHostUserInterface
|
|
{
|
|
private StringBuilder _buffer;
|
|
private CustomPSHostRawUserInterface _rawUI;
|
|
|
|
private delegate void WriteChannel(Int64 context, byte[] buffer);
|
|
private WriteChannel _chanWriter = null;
|
|
private Int64 _context = 0;
|
|
|
|
public CustomPSHostUserInterface()
|
|
{
|
|
_buffer = new StringBuilder();
|
|
_rawUI = new CustomPSHostRawUserInterface();
|
|
}
|
|
|
|
public bool IsChannelised
|
|
{
|
|
get { return _chanWriter != null; }
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return _buffer.ToString();
|
|
}
|
|
|
|
public void Channelise(Int64 channelWriter, Int64 context)
|
|
{
|
|
_chanWriter = (WriteChannel)Marshal.GetDelegateForFunctionPointer(new IntPtr(channelWriter), typeof(WriteChannel));
|
|
_context = context;
|
|
}
|
|
|
|
public void Unchannelise()
|
|
{
|
|
_chanWriter = null;
|
|
_context = 0;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
_buffer.Remove(0, _buffer.Length);
|
|
}
|
|
|
|
public override Dictionary<string, System.Management.Automation.PSObject> Prompt(string caption, string message, System.Collections.ObjectModel.Collection<FieldDescription> descriptions)
|
|
{
|
|
return new Dictionary<string, System.Management.Automation.PSObject>();
|
|
}
|
|
|
|
public override int PromptForChoice(string caption, string message, System.Collections.ObjectModel.Collection<ChoiceDescription> choices, int defaultChoice)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public override System.Management.Automation.PSCredential PromptForCredential(string caption, string message, string userName, string targetName, System.Management.Automation.PSCredentialTypes allowedCredentialTypes, System.Management.Automation.PSCredentialUIOptions options)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override System.Management.Automation.PSCredential PromptForCredential(string caption, string message, string userName, string targetName)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override PSHostRawUserInterface RawUI
|
|
{
|
|
get { return _rawUI; }
|
|
}
|
|
|
|
public override string ReadLine()
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
public override System.Security.SecureString ReadLineAsSecureString()
|
|
{
|
|
return new System.Security.SecureString();
|
|
}
|
|
|
|
public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string message)
|
|
{
|
|
WriteTarget(message.TrimEnd());
|
|
}
|
|
|
|
public override void Write(string message)
|
|
{
|
|
WriteTarget(message.TrimEnd());
|
|
}
|
|
|
|
public void WriteRaw(string message)
|
|
{
|
|
WriteTarget(message);
|
|
}
|
|
|
|
public override void WriteDebugLine(string message)
|
|
{
|
|
WriteTarget(string.Format("DEBUG: {0}\n", message.TrimEnd()));
|
|
}
|
|
|
|
public override void WriteErrorLine(string message)
|
|
{
|
|
WriteTarget(string.Format("ERROR: {0}\n", message.TrimEnd()));
|
|
}
|
|
|
|
public override void WriteLine(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string message)
|
|
{
|
|
WriteTarget(string.Format("{0}\n", message.TrimEnd()));
|
|
}
|
|
|
|
public override void WriteLine(string message)
|
|
{
|
|
WriteTarget(string.Format("{0}\n", message.TrimEnd()));
|
|
}
|
|
|
|
public override void WriteLine()
|
|
{
|
|
WriteTarget("\n");
|
|
}
|
|
|
|
public override void WriteProgress(long sourceId, System.Management.Automation.ProgressRecord record)
|
|
{
|
|
}
|
|
|
|
public override void WriteVerboseLine(string message)
|
|
{
|
|
WriteTarget(string.Format("VERBOSE: {0}\n", message.TrimEnd()));
|
|
}
|
|
|
|
public override void WriteWarningLine(string message)
|
|
{
|
|
WriteTarget(string.Format("WARNING: {0}\n", message.TrimEnd()));
|
|
}
|
|
|
|
private void WriteTarget(string message)
|
|
{
|
|
if (IsChannelised)
|
|
{
|
|
var bytes = System.Text.Encoding.ASCII.GetBytes(message);
|
|
System.Diagnostics.Debug.WriteLine(string.Format("[PSH BINDING] Writing to channel {0:X} -{1}", _context, message));
|
|
_chanWriter(_context, bytes);
|
|
}
|
|
else
|
|
{
|
|
//System.Diagnostics.Debug.WriteLine("[PSH BINDING] Writing to buffer: " + message);
|
|
_buffer.Append(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class CustomPSHostRawUserInterface : PSHostRawUserInterface
|
|
{
|
|
|
|
public override ConsoleColor BackgroundColor
|
|
{
|
|
get { return ConsoleColor.Black; }
|
|
set { }
|
|
}
|
|
|
|
public override Size BufferSize
|
|
{
|
|
get { return new Size(120, 100); }
|
|
set { }
|
|
}
|
|
|
|
public override Coordinates CursorPosition
|
|
{
|
|
get { return new Coordinates(0, 0); }
|
|
set { }
|
|
}
|
|
|
|
public override int CursorSize
|
|
{
|
|
get { return 1; }
|
|
set { }
|
|
}
|
|
|
|
public override void FlushInputBuffer()
|
|
{
|
|
}
|
|
|
|
public override ConsoleColor ForegroundColor
|
|
{
|
|
get { return ConsoleColor.White; }
|
|
set { }
|
|
}
|
|
|
|
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
|
|
{
|
|
return new BufferCell[0,0];
|
|
}
|
|
|
|
public override bool KeyAvailable
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public override Size MaxPhysicalWindowSize
|
|
{
|
|
get { return new Size(int.MaxValue, int.MaxValue); }
|
|
}
|
|
|
|
public override Size MaxWindowSize
|
|
{
|
|
get { return new Size(120, 100); }
|
|
}
|
|
|
|
public override KeyInfo ReadKey(ReadKeyOptions options)
|
|
{
|
|
return new KeyInfo();
|
|
}
|
|
|
|
public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill)
|
|
{
|
|
}
|
|
|
|
public override void SetBufferContents(Rectangle rectangle, BufferCell fill)
|
|
{
|
|
}
|
|
|
|
public override void SetBufferContents(Coordinates origin, BufferCell[,] contents)
|
|
{
|
|
}
|
|
|
|
public override Coordinates WindowPosition
|
|
{
|
|
get { return new Coordinates(-200, -200); }
|
|
set { }
|
|
}
|
|
|
|
public override Size WindowSize
|
|
{
|
|
get { return new Size(120, 100); }
|
|
set { }
|
|
}
|
|
|
|
public override string WindowTitle
|
|
{
|
|
get { return string.Empty; }
|
|
set { }
|
|
}
|
|
}
|
|
}
|
|
}
|