1+ class TuoniPayload :
2+ """
3+ A class that provides data and functionality for a sent payload.
4+
5+ Attributes:
6+ payload_id (int): The unique identifier of the payload.
7+ template_id (str): The unique identifier of the payload template used to create the payload.
8+ template_name (str): The name of the payload template used to create the payload.
9+ configuration (dict): The configuration settings for the payload.
10+ listeners (list): The listeners associated with the payload.
11+ os (str): The operating system for the payload.
12+ architecture (str): The architecture for the payload.
13+ status (str): The status of the payload.
14+ encrypted_communication (bool): Indicates if the communication is encrypted.
15+
16+ Examples:
17+ Create a payload from a conf dict and save it to disk:
18+
19+ >>> payload = TuoniPayload(
20+ ... conf={
21+ ... "templateId": "shelldot.payload.windows-x64",
22+ ... "configuration": {"type": "executable"}
23+ ... },
24+ ... c2=tuoni_c2
25+ ... )
26+ >>> payload.create(listener_id=1)
27+ >>> print(f"Created payload with ID: {payload.payload_id}")
28+ >>>
29+ >>> # Download and save the payload binary
30+ >>> data = payload.download()
31+ >>> with open("agent.exe", "wb") as f:
32+ ... f.write(data)
33+ >>>
34+ >>> # Delete the payload when done
35+ >>> payload.delete()
36+ """
37+
38+ def __init__ (self , conf = None , c2 = None ):
39+ """
40+ Constructor for the payload class.
41+
42+ Args:
43+ conf (dict): A dict to initialize the payload from. When passed a server
44+ response all fields are populated. When passed a user-provided creation
45+ dict, only ``templateId`` and ``configuration`` are required; ``name``,
46+ ``encryptedCommunication`` (default ``True``), and
47+ ``configurationFiles`` (default ``[]``) are optional.
48+ c2 (TuoniC2): The related server object that manages communication.
49+ """
50+ self .payload_id = None
51+ self .name = None
52+ self .template_id = None
53+ self .configuration = {}
54+ self .configuration_files = []
55+ self .encrypted_communication = True
56+ self .c2 = c2
57+ if conf is not None :
58+ self ._load_conf (conf )
59+
60+ def _load_conf (self , conf ):
61+ self .payload_id = conf .get ("id" , None )
62+ self .name = conf .get ("name" , None )
63+ self .template_id = conf .get ("templateId" , self .template_id )
64+ self .configuration = conf .get ("configuration" , self .configuration )
65+ self .listeners = conf .get ("listeners" , [])
66+ self .os = conf .get ("os" , None )
67+ self .architecture = conf .get ("architecture" , None )
68+ self .status = conf .get ("status" , None )
69+ self .encrypted_communication = conf .get ("encryptedCommunication" , self .encrypted_communication )
70+ self .configuration_files = conf .get ("configurationFiles" , self .configuration_files )
71+
72+ def load (self , id ):
73+ """
74+ Load the payload data from the C2 server using the payload ID.
75+
76+ Args:
77+ id (int): The unique identifier of the payload to load.
78+ """
79+ data = self .c2 .request_get (f"/api/v1/payloads/{ id } " )
80+ self ._load_conf (data )
81+
82+ def create (self , listener_id ):
83+ """
84+ Create the payload on the C2 server.
85+
86+ Args:
87+ listener_id (int): The ID of the listener to associate with this payload.
88+
89+ Examples:
90+ >>> payload = TuoniPayload(
91+ ... conf={
92+ ... "templateId": "shelldot.payload.windows-x64",
93+ ... "configuration": {"type": "executable"}
94+ ... },
95+ ... c2=tuoni_c2
96+ ... )
97+ >>> payload.create(listener_id=1)
98+ """
99+ if self .payload_id is not None :
100+ raise Exception ("Payload already created." )
101+ data = self .c2 .request_post ("/api/v1/payloads" , {
102+ "payloadTemplateId" : self .template_id ,
103+ "name" : self .name ,
104+ "configuration" : self .configuration ,
105+ "configurationFiles" : self .configuration_files ,
106+ "listenerId" : listener_id ,
107+ "encrypted" : self .encrypted_communication
108+ })
109+ self ._load_conf (data )
110+
111+ def delete (self ):
112+ """
113+ Delete the payload from the C2 server.
114+ """
115+ if self .payload_id is None :
116+ raise Exception ("Payload not created." )
117+ self .c2 .request_delete (f"/api/v1/payloads/{ self .payload_id } " )
118+ self .payload_id = None
119+
120+ def update (self ):
121+ """
122+ Update the payload configuration on the C2 server.
123+
124+ Args:
125+ new_configuration (dict): The new configuration settings for the payload.
126+ """
127+ if self .payload_id is None :
128+ raise Exception ("Payload not created." )
129+ data = self .c2 .request_patch (f"/api/v1/payloads/{ self .payload_id } " , {
130+ "name" : self .name
131+ })
132+ self ._load_conf (data )
133+
134+ def download (self ):
135+ """
136+ Download the payload from the C2 server.
137+
138+ Returns:
139+ bytes: The binary data of the downloaded payload.
140+ """
141+ if self .payload_id is None :
142+ raise Exception ("Payload not created." )
143+ return self .c2 .request_get (f"/api/v1/payloads/{ self .payload_id } /download" , result_as_json = False , result_as_bytes = True )
0 commit comments