Creating Real Looking User Accounts in AD Lab

As I write my own tools for IR Hunting and Post-Expoitation I like to have a large realistic set of AD accounts and also accounts with accentuated and not english characters to make sure my tools will work in large environments and also simulate multiple geographical locations since most customers are not US based. When creating realistic user accounts I have found no better source that using http://www.fakenamegenerator.com it allows me to order a CSV with a large amount of realistic looking users and their details.  

To do this I first go to the Fake Name Generator page and select from the menu the Order in Bulk option, click on the checkbox to accept the terms of services and select as output Comma separated (.csv)

Now on step 3 I can select the name set and the country for the account information I want. Once that is selected I then select the following fields:

  • GivenName
  • Surname
  • StreetAddress
  • City
  • Title
  • Username
  • Password
  • Country
  • TelephoneNumber
  • Occupation 

Once the fields have been selected I simply specify the number, the email and enter the captcha to get the accounts via email. 

Now once I have the CSV in my experience they tend to have repeated usernames, also I have found my self missing one or more of the fields when I selected what to include in the CSV so I wrote a series of PowerShell functions I can use when working with the data. 

The first function is a simple one that allows me to test that the CSV contains all the fields I want. It simply extracts the header from the CSV and checks against a list. 

<#

.Synopsis

   Test a CSV from FakeNameGenerator.com for required fields.

.DESCRIPTION

  Test a CSV from FakeNameGenerator.com for required fields.

.EXAMPLE

   Test-LabADUserList -Path .\FakeNameGenerator.com_b58aa6a5.csv

#>

function Test-LabADUserList

{

    [CmdletBinding()]

    [OutputType([Bool])]

    Param

    (

        [Parameter(Mandatory=$true,

                   Position=0,

                   ValueFromPipeline=$true,

                   ValueFromPipelineByPropertyName=$true,

                   HelpMessage="Path to CSV generated from fakenamegenerator.com.")]

        [Alias("PSPath")]

        [ValidateNotNullOrEmpty()]

        [string]

        $Path

    )

    Begin {}

    Process

    {

        # Test if the file exists.

        if (Test-Path -Path $Path -PathType Leaf)

        {

            Write-Verbose -Message "Testing file $($Path)"

        }

        else

        {

            Write-Error -Message "File $($Path) was not found or not a file."

            $false

            return

        }

        # Get CSV header info.

        $fileinfo = Import-Csv -Path $Path | Get-Member | Select-Object -ExpandProperty Name

        $valid = $true

        

            

        if ('City' -notin $fileinfo) {

            Write-Warning -Message 'City field is missing'

            $valid =  $false

        }

        if ('Country' -notin $fileinfo) {

            Write-Warning -Message 'Country field is missing'

            $valid =  $false

        }

        if ('GivenName' -notin $fileinfo) {

            Write-Warning -Message 'GivenName field is missing'

            $valid =  $false

        }

        if ('Occupation' -notin $fileinfo) {

            Write-Warning -Message 'Occupation field is missing'

            $valid =  $false

        }

        if ('Password' -notin $fileinfo) {

            Write-Warning -Message 'Password field is missing'

            $valid =  $false

        }

        if ('StreetAddress' -notin $fileinfo) {

            Write-Warning -Message 'StreetAddress field is missing'

            $valid =  $false

        }

        if ('Surname' -notin $fileinfo) {

            Write-Warning -Message 'Surname field is missing'

            $valid =  $false

        }

        if ('TelephoneNumber' -notin $fileinfo) {

            Write-Warning -Message 'TelephoneNumber field is missing'

            $valid =  $false

        }

        if ('Username' -notin $fileinfo) {

            Write-Warning -Message 'Username field is missing'

            $valid =  $false

        }

        $valid

    }

    End {}

}


The next function will remove any duplicate username entries, I have found with large samples that it is inevitable for some of the usernames to be duplicated. This function uses a lot the pipeline so as minimize memory use, not the fastest but when dealing with several thousands of fake user details in a VM environment with limited memory it becomes an acceptable tradeoff.

<#

.Synopsis

   Removes duplicate username entries from Fake Name Generator generated accounts.

.DESCRIPTION

   Removes duplicate username entries from Fake Name Generator generated accounts. Bulk

   generated accounts from fakenamegenerator.com must have as fields:

   * GivenName

   * Surname

   * StreetAddress

   * City

   * Title

   * Username

   * Password

   * Country

   * TelephoneNumber

   * Occupation

.EXAMPLE

    Remove-LabADUsertDuplicate -Path .\FakeNameGenerator.com_b58aa6a5.csv -OutPath .\unique_users.csv

#>

function Remove-LabADUsertDuplicate

{

    [CmdletBinding()]

    Param

    (

        [Parameter(Mandatory=$true,

                   Position=0,

                   ParameterSetName="Path",

                   ValueFromPipeline=$true,

                   ValueFromPipelineByPropertyName=$true,

                   HelpMessage="Path to CSV to remove duplicates from.")]

        [Alias("PSPath")]

        [ValidateNotNullOrEmpty()]

        [string]

        $Path,

        [Parameter(Mandatory=$true,

                   Position=1,

                   ParameterSetName="Path",

                   ValueFromPipeline=$true,

                   ValueFromPipelineByPropertyName=$true,

                   HelpMessage="Path to CSV to remove duplicates from.")]

        [ValidateNotNullOrEmpty()]

        [string]

        $OutPath

    )

    Begin {}

    Process

    {

        Write-Verbose -Message "Processing $($Path)"

        if (Test-LabADUserList -Path $Path) {

            Import-Csv -Path $Path | Group-Object Username | Foreach-Object {

                $_.group | Select-Object -Last 1} | Export-Csv -Path $OutPath -Encoding UTF8

        } else {

            Write-Error -Message "File $($Path) is not valid."

        }

        

    }

    End {}

}


The last function does the importing of accounts from the processed CSV with duplicate usernames removed in to a specified OU. The function will create OUs under the specified one for each country in the account set. 

<#

.SYNOPSIS

    Imports a CSV from Fake Name Generator to create test AD User accounts.

.DESCRIPTION

    Imports a CSV from Fake Name Generator to create test AD User accounts.

    It will create OUs per country under the OU specified. Bulk

   generated accounts from fakenamegenerator.com must have as fields:

   * GivenName

   * Surname

   * StreetAddress

   * City

   * Title

   * Username

   * Password

   * Country

   * TelephoneNumber

   * Occupation

.EXAMPLE

    C:\PS> Import-LabADUser -Path .\unique.csv -OU DemoUsers

#>

function Import-LabADUser

{

    [CmdletBinding()]

    param(

        [Parameter(Mandatory=$true,

                   Position=0,

                   ValueFromPipeline=$true,

                   ValueFromPipelineByPropertyName=$true,

                   HelpMessage="Path to one or more locations.")]

        [Alias("PSPath")]

        [ValidateNotNullOrEmpty()]

        [string[]]

        $Path,

        [Parameter(Mandatory=$true,

                   position=1,

                   ValueFromPipeline=$true,

                   ValueFromPipelineByPropertyName=$true,

                   HelpMessage="Organizational Unit to save users.")]

        [String]

        [Alias('OU')]

        $OrganizationalUnit

    )

    

    begin {

        

    }

    

    process {

        Import-Module ActiveDirectory

        if (-not (Get-Module -Name 'ActiveDirectory')) {

            return

        }

        $DomDN = (Get-ADDomain).DistinguishedName

        $forest = (Get-ADDomain).Forest

        $ou = Get-ADOrganizationalUnit -Filter "name -eq '$($OrganizationalUnit)'"

        if($ou -eq $null) {

            New-ADOrganizationalUnit -Name "$($OrganizationalUnit)" -Path $DomDN

            $ou = Get-ADOrganizationalUnit -Filter "name -eq '$($OrganizationalUnit)'"

        }

        $data =

        Import-Csv -Path $Path | select  @{Name="Name";Expression={$_.Surname + ", " + $_.GivenName}},

                @{Name="SamAccountName"; Expression={$_.Username}},

                @{Name="UserPrincipalName"; Expression={$_.Username +"@" + $forest}},

                @{Name="GivenName"; Expression={$_.GivenName}},

                @{Name="Surname"; Expression={$_.Surname}},

                @{Name="DisplayName"; Expression={$_.Surname + ", " + $_.GivenName}},

                @{Name="City"; Expression={$_.City}},

                @{Name="StreetAddress"; Expression={$_.StreetAddress}},

                @{Name="State"; Expression={$_.State}},

                @{Name="Country"; Expression={$_.Country}},

                @{Name="PostalCode"; Expression={$_.ZipCode}},

                @{Name="EmailAddress"; Expression={$_.Username +"@" + $forest}},

                @{Name="AccountPassword"; Expression={ (Convertto-SecureString -Force -AsPlainText $_.password)}},

                @{Name="OfficePhone"; Expression={$_.TelephoneNumber}},

                @{Name="Title"; Expression={$_.Occupation}},

                @{Name="Enabled"; Expression={$true}},

                @{Name="PasswordNeverExpires"; Expression={$true}} | ForEach-Object -Process {

            

                    $subou = Get-ADOrganizationalUnit -Filter "name -eq ""$($_.Country)""" -SearchBase $ou.DistinguishedName        

                    if($subou -eq $null) {

                        New-ADOrganizationalUnit -Name $_.Country -Path $ou.DistinguishedName

                        $subou = Get-ADOrganizationalUnit -Filter "name -eq ""$($_.Country)""" -SearchBase $ou.DistinguishedName        

                    }

                    $_ | Select @{Name="Path"; Expression={$subou.DistinguishedName}},* | New-ADUser  

                }

    }    

    end {}

}


The PS1 file with the functions can be found in my GitHub account https://github.com/darkoperator/powershell_scripts/blob/master/LabAccountImport.ps1 once you download a copy of it you only need to dot source the file on a PowerShell session on the Windows 2012 R2 domain controller where you want to import the accounts:

PS C:\> . .\LabAccountImport.ps1

Now the functions will be available for you to use in the interactive session. We start by testing the file we got via email to make sure it has all the fields we want and that no mistakes where done when ordering the names:

PS C:\> Test-LabADUserList -Path .\FakeNameGenerator.com_b58aa6a5.csv
True

Now we create a new CSV file with unique usernames:

PS C:\> Remove-LabADUsertDuplicate -Path .\FakeNameGenerator.com_b58aa6a5.csv -OutPath .\UniqueUY.csv

Once we have the accounts with unique usernames we can import de file in to Active Directory:

PS C:\> Import-LabADUser -Path .\UniqueUY.csv -OrganizationalUnit DemoUsers

Once it finishes you should now have a nice set of test accounts in AD for you to use. 

Of the 3,000 accounts only 2,182 where unique when it came to username, still a very good number for testing. In the future I will probably make it so when it finds accounts with repeated usernames, Surnames or LastNames to add a random string to each. 

As Always I hope you find the information useful.