The Unofficial NT Hack FAQ

[ Return to TOC | Return to FAQ Page ]


Appendix Section

A-01. Source Code for an Audit Script


This source was originally posted to ISS' NT Security mailing list, and I've lost the original author of the code. Anyway, here it is reproduced without permission, but then again it's probably in a mailing list archive somewhere anyway... ;-)

# Audit accounts, privileges, servers, workstations, and trust relationships
# of a domain.  The domain name can be specified as an argument, or else the
# current domain will be used

# load extensions
# load Christopher Sedore's NT extensions (the system portion)
load ntsys.dll

# Proceedure forward definitions

# check if account is enabled - returns the string "ENABLED" or "DISABLED"
# there is a special case if accountinfolist is set to 0.  the string "GROUP"
# is returned in this case.
proc checkAccountStatus {accountinfolist} {
     if {$accountinfolist == 0} then {set enablestatus "GROUP "; return
$enablestatus;}
     if {[lsearch -glob $accountinfolist
{*[U][F][_][A][C][C][O][U][N][T][D][I][S][A][B][L][E]*}] < 0} \
     then {set enablestatus "ENABLED"} \
     else {set enablestatus "DISABLED"};
     return $enablestatus;
}

# print list. If list length is 0, then "NONE" is printed.
proc printList {list printdest} {
     set listindex 0;
     if {[llength $list] == 0} then {puts $printdest "NONE"; return;};
     while {$listindex < [llength $list]} {
          puts $printdest "[lindex $list $listindex]";
          incr listindex;
     }
}

# print list with account status check
# NT_UserGetInfo is called first with the account name given in list, if that fails
# then it might be a local account so the machine name and "\" are stripped off the
# front and NT_UserGetInfo is called again. If that fails then we set accountinfolist
# to 0.
proc printListWithAccountStatus {list printdest server} {
     upvar pdc p_pdc;
     set listindex 0;
     if {[llength $list] == 0} then {puts $printdest "NONE"; return;};
     while {$listindex < [llength $list]} {
          if {[catch {set accountinfolist [NT_UserGetInfo $server [lindex $list
$listindex]]}] != 0} \
          then {set cleanname [string trimleft [lindex $list $listindex] [string
trimleft $server "\\"]];
                if {[catch {set accountinfolist [NT_UserGetInfo $server [string
trimleft $cleanname "\\"]]}] != 0} then {set accountinfolist 0}};
          puts $printdest "[lindex $list $listindex] : [checkAccountStatus
$accountinfolist]";
          incr listindex;
     }
}

# clean up machine account list
proc cleanMachineAccountList {machinelist} {
     set listindex 0;
     set templist {};
     while {$listindex < [llength $machinelist]} {
          set templist [concat $templist [lindex $machinelist $listindex]];
          incr listindex;
     }

     set listindex 0;
     set list {};
     while {$listindex < [llength $templist]} {
          set list [concat $list [string trimright [format "\\\\\\\\%s" [lindex
$templist $listindex]] {$}]];
          incr listindex 3;
     }
     return $list;
}

# MAIN CODE

# check command line args and set domain to that specified on the cmdline, or
# else a empty string (to represent the current domain)
if {$argc > 0} then {set logfile [lindex $argv 0]} else {set logfile {c:\AuditLog.txt}}
if {$argc == 2} then {set domain [lindex $argv 1]} else {set domain {}}

# open audit log file
set auditlog [open $logfile a+]

# find Primary Domain Controller
set pdc [NT_GetDCName $domain]

# print tag for DOMAIN STATISTICS section
puts $auditlog "\[DOMAIN STATISTICS\]\n"

# get DCs and clean up list for printing
set dclist [cleanMachineAccountList [NT_UserEnum $pdc
{FILTER_SERVER_TRUST_ACCOUNT}]]

# print them out
puts $auditlog "Domain Controllers:\n"
printList $dclist $auditlog

# print PDC name
puts $auditlog "\nPrimary Domain Controller:\n\n$pdc\n"

# get domain user accounts
set userlist [NT_UserEnum $pdc {}]

# print user list
puts $auditlog "\nDomain Users:\n"
printList $userlist $auditlog

# get groups defined in the domain
set grouplist [NT_GroupEnum $pdc]

# print group list
puts $auditlog "\nGroups defined in the domain:\n"
printList $grouplist $auditlog

# print users in each group and the account status
set listindex 0
while {$listindex < [llength $grouplist]} {
     set templist [NT_GroupGetUsers $pdc [lindex $grouplist $listindex]];
     puts $auditlog "\nUsers in the \"[lindex $grouplist $listindex]\" group:\n";
     printListWithAccountStatus $templist $auditlog $pdc;
     incr listindex;
}

# get machine accounts in domain for workstations and non-DC servers
set wrkstalist [cleanMachineAccountList [NT_UserEnum $pdc
{FILTER_WORKSTATION_TRUST_ACCOUNT}]]

# print them out
puts $auditlog "\nWorkstations and non-DC servers in the domain:\n"
printList $wrkstalist $auditlog

# get trust relationships
set trustlist [cleanMachineAccountList [NT_UserEnum $pdc
{FILTER_INTERDOMAIN_TRUST_ACCOUNT}]]

# print them out
puts $auditlog "\nDomains with which trust relationships are configured:\n"
printList $trustlist $auditlog

# move on to machine statistics
puts $auditlog "\n\[MACHINE STATISTICS\]\n"

# do domain controllers
# put in error handling for RPC server unavailable for NT_LocalGroupEnum
set listindex 0
while {$listindex < [llength $dclist]} {
     if {[catch {NT_LocalGroupEnum [lindex $dclist $listindex]}machinegrouplist]} \
     then {puts $auditlog "\n[lindex $dclist $listindex] unavailable";
           incr listindex;
           continue;};
     puts $auditlog "\n[lindex $dclist $listindex] groups:\n";
     printList $machinegrouplist $auditlog;

     set tempindex 0;
     while {$tempindex < [llength $machinegrouplist]} {
          set templist [NT_LocalGroupGetUsers [lindex $dclist $listindex] [lindex
$machinegrouplist $tempindex]];
          puts $auditlog "\nUsers in the \"[lindex $machinegrouplist $tempindex]\"group:\n";
          printListWithAccountStatus $templist $auditlog [lindex $dclist $listindex];
          incr tempindex;
     }
     incr listindex;
}

# do workstations and non-DC servers controllers
set listindex 0
while {$listindex < [llength $wrkstalist]} {
     if {[catch {NT_LocalGroupEnum [lindex $wrkstalist $listindex]}machinegrouplist]} \
     then {puts $auditlog "\n[lindex $wrkstalist $listindex] unavailable";
           incr listindex;
           continue;};
     puts $auditlog "\n[lindex $wrkstalist $listindex] groups:\n";
     printList $machinegrouplist $auditlog;

     set tempindex 0;
     while {$tempindex < [llength $machinegrouplist]} {
          set templist [NT_LocalGroupGetUsers [lindex $wrkstalist $listindex]
[lindex $machinegrouplist $tempindex]];
          puts $auditlog "\nUsers in the \"[lindex $machinegrouplist $tempindex]\"group:\n";
          printListWithAccountStatus $templist $auditlog [lindex $wrkstalist
$listindex];
          incr tempindex;
     }
     incr listindex;
}

close $auditlog

[ Return to TOC | Return to FAQ Page ]