mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-24 18:16:24 +01:00

I stuffed up when dealing with values that are being passed back and forth across components when in x86 processes. I was passing 64 bit ints around even in 32 bit mode, which resulted in some natstiness. This commit fixes that problem by forcing everything to be 64 bit regardless of arch, and casting to the appropriate pointer at the right time.
459 lines
15 KiB
C#
Executable File
459 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();
|
|
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 { }
|
|
}
|
|
}
|
|
}
|
|
}
|