Friday, August 4, 2017

Creating Self-Updating PowerShell Scripts with GitHub

Begin {}


TL;DR - This article describes my method for automatically updating a user's cloned PowerShell script using a custom PS1 update script, github, and some sneaky versioning techniques. Basically, I wanted to be able to have my PowerShell script read my github repo, pull down & install any updates, and ensure convenience to the user.

Luckystrike is a PowerShell-based pentesting tool used to generate malicious macro documents. It stores user created payloads and templates in a local sqlite database. This makes it convenient for the user to reuse the same payloads and templates across engagements.

The decision to use a sqlite database presented an interesting design challenge when it came to updates. How would I pull a new copy of the script down? What if I updated the sqlite schema? Would I delete/recreate the local db and force the user to have to re-add everything? I didn't want to do this because not only is it terribly inconvenient for the user, but I'm a developer and this seemed like a solvable problem! I saw several options that allowed me to do simple updates, but nothing comprehensive like I wanted, so I decided to code my own solution (I now think Chocolatey might be able to do this, but didn't know it existed at the time).

Process {}




The update process is as follows:
  1. When launched, luckystrike verifies an internet connection.
  2. It then checks a file in the repo, currentversion.txt, and compares that value to its local hardcoded value.
  3. If the repo value is greater, update.ps1 is downloaded from the repo and saved to the running directory.
  4. Luckystrike fires update.ps1 is fired in a new process, then exits itself.
  5. The update script calls the garbage collector (critical for clean sqlite work), downloads a new version of the schema, creates a new db based off the schema, performs db transfers, then grabs a new copy of luckystrike.ps1
  6. Bob's your uncle.
The bulk of the work happens in two functions, UpdatesAvailable() and Process-Updates() (please, no comments about "proper" function naming. I'm working on it :-).

I'm posting screenshots here to keep things easy. All the code is available on github in luckystrike.ps1


Except for my janky version comparison method, the UpdatesAvailable() method is pretty straightforward. Download the string for the HTTP path in my $githubver (in this case "2.0", retrieved from https://raw.githubusercontent.com/curi0usJack/luckystrike/master/currentversion.txt), then compare it against my $version var, in this case "1.1.7". While I'm sure there are far better ways to do it, the version comparison method allows for major, minor, and incremental versioning. It simply returns a boolean indicating if updates are available or not.

This method is consumed by the Process-Updates() method:



Pretty simple. This method checks for an internet connection, downloads the update file (https://raw.githubusercontent.com/curi0usJack/luckystrike/master/update.ps1), runs that update file in a new process, then exits.

Update.ps1 performs all the customized database work I need, ensuring the process is painless to the user. Once it's done and the user launches luckystrike again, update.ps1 is deleted.

Here's what the update process looks like to the user:



End {}


The nice thing about this is that everything is controlled by currentversion.txt. You can test the entire update process, even after push your changes to master, without impacting the users in case you find a bug. Once you push all your changes, simply set your local version variable to something lower than the currentversion.txt file on github and launch. You'll be prompted to update and you can do your testing. Once everything is working and all pushes are done, the last thing to update is currentversion.txt. Only then will users be prompted to update!

If you got this far, hopefully you found some value out of this. I'm sure there are much easier ways of going about solving this problem, but this worked (and continues to work) for me!

@curi0usJack

Sunday, July 23, 2017

Luckystrike 2.0 is here!

tl;dr: Luckystrike is an open source evil macro generation utility written in PowerShell. Originally released at DerbyCon 6.0. Updates include Word support & new attacks.

Code is here.
Original blog post here.
Derbycon talk here (luckystrike begins at 18:45)

New Features:

  1. Full support for Microsoft Word output (.doc), as well as Word-based template storage.
  2. Support for Invoke-Obfuscation of PowerShell based payloads as well as PowerShell Shell commands (e.g. powershell -nop -enc ...)
  3. New Payload Type: COM Scriptlets. Receives a URL that points to your scriptlet and can fire it via the following Infection Types (based on amazing @subTee research):
    1. Pubprn.vbs - Example
    2. Regsrv32 - Example
  4. Excel DDE Infection Type added: Research. Note that your first Shell Command payload word is the command run by DDE.
  5. A truckload of bug fixes
  6. Luckystrike's -API switch allows it to be scriptable. See my Pester script for examples.
  7. I also filled out the wiki to make it easy to get assistance.

First-time Installation


I highly encourage you to read the wiki before installing, but if you're antsy, you can install with this PowerShell command (run in an admin context):

iex (new-object net.webclient).downloadstring('https://git.io/v7kbp')

Upgrading


Normally luckystrike will prompt you when there is a new upgrade. However, I just switched repos, so this creates a problem. Easiest is just to install new, but if you have templates/payloads that you want to preserve, you can upgrade easily by opening luckystrike.ps1 in an editor and change the old repo location to the new repo location. Once you save/close/relaunch, luckystrike will pick up the changes from the new repo and prompt you to upgrade.

Old Repo:


New Repo:



Getting Help


If you encounter an error and/or need other assistance, please run luckystrike with the -Debug switch. It will create a debug log that you must upload with your github issue, otherwise you can expect me to not respond!

I do not offer help in making payloads. Please stop asking.

Credits


Huge thanks to Casey Smith for continuing to put out awesome research, Daniel Bohannon for incredible obfuscation work, and Steve McKenzie for help testing and git-fu. <3 you guys!