Land #3085, service_control support

This depends on rapid7/meterpreter#77 to function
bug/bundler_fix
Tod Beardsley 2014-03-19 08:43:17 -05:00
commit 8e7f12e30e
No known key found for this signature in database
GPG Key ID: 1EFFB682ADB9F193
3 changed files with 120 additions and 35 deletions

View File

@ -15,18 +15,26 @@ module Service
###
class Service
SERVICE_OP_START = 1
SERVICE_OP_PAUSE = 2
SERVICE_OP_RESUME = 3
SERVICE_OP_STOP = 4
SERVICE_OP_RESTART = 5
def initialize(client)
@client = client
end
#
# Enumerate all the services on the target.
#
def enumerate
request = Packet.create_request('extapi_service_enum')
response = client.send_request(request)
services = []
response.each(TLV_TYPE_EXT_SERVICE_ENUM_GROUP) { |s|
response.each(TLV_TYPE_EXT_SERVICE_ENUM_GROUP) do |s|
services << {
:name => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_NAME),
:display => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME),
@ -34,29 +42,59 @@ class Service
:status => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_STATUS),
:interactive => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE)
}
}
end
return services.sort_by { |s| s[:name].upcase }
services.sort_by { |s| s[:name].upcase }
end
#
# Query some detailed parameters about a particular service.
#
def query(service_name)
request = Packet.create_request('extapi_service_query')
request.add_tlv(TLV_TYPE_EXT_SERVICE_ENUM_NAME, service_name)
response = client.send_request(request)
detail = {
{
:starttype => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE),
:display => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME),
:startname => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME),
:path => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_PATH),
:logroup => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP),
:interactive => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE),
:dacl => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DACL)
:dacl => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DACL),
:status => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STATUS)
}
end
return detail
#
# Control a single service
#
def control(service_name, op)
if op.is_a? String
case op.strip.downcase
when "start"
op = SERVICE_OP_START
when "pause"
op = SERVICE_OP_PAUSE
when "resume"
op = SERVICE_OP_RESUME
when "stop"
op = SERVICE_OP_STOP
when "restart"
op = SERVICE_OP_RESTART
end
end
unless (op.is_a? Integer) && op >= SERVICE_OP_START && op <= SERVICE_OP_RESTART
raise ArgumentError, "Invalid operation: #{op}"
end
request = Packet.create_request('extapi_service_control')
request.add_tlv(TLV_TYPE_EXT_SERVICE_CTRL_NAME, service_name)
request.add_tlv(TLV_TYPE_EXT_SERVICE_CTRL_OP, op)
client.send_request(request)
end
attr_accessor :client

View File

@ -27,6 +27,10 @@ TLV_TYPE_EXT_SERVICE_QUERY_PATH = TLV_META_TYPE_STRING | (TLV_TYPE_E
TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 24)
TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 25)
TLV_TYPE_EXT_SERVICE_QUERY_DACL = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 26)
TLV_TYPE_EXT_SERVICE_QUERY_STATUS = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 27)
TLV_TYPE_EXT_SERVICE_CTRL_NAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 28)
TLV_TYPE_EXT_SERVICE_CTRL_OP = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 29)
TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 35)

View File

@ -22,8 +22,9 @@ class Console::CommandDispatcher::Extapi::Service
#
def commands
{
"service_enum" => "Enumerate all registered Windows services",
"service_query" => "Query more detail about a specific Windows service"
"service_enum" => "Enumerate all registered Windows services",
"service_query" => "Query more detail about a specific Windows service",
"service_control" => "Control a single service (start/pause/resume/stop/restart)"
}
end
@ -33,6 +34,32 @@ class Console::CommandDispatcher::Extapi::Service
def name
"Extapi: Service Management"
end
#
# Initialize the instance
#
def initialize(shell)
super
@status_map = {
1 => "Stopped",
2 => "Starting",
3 => "Stopping",
4 => "Running",
5 => "Continuing",
6 => "Pausing",
7 => "Paused"
}
@start_type_map = {
0 => "Boot",
1 => "System",
2 => "Automatic",
3 => "Manual",
4 => "Disabled"
}
end
#
# Options for the service_enum command.
#
@ -44,7 +71,7 @@ class Console::CommandDispatcher::Extapi::Service
# Query a single service for more detail.
#
def cmd_service_enum(*args)
@@service_enum_opts.parse(args) { |opt, idx, val|
@@service_enum_opts.parse(args) do |opt, idx, val|
case opt
when "-h"
print(
@ -55,17 +82,7 @@ class Console::CommandDispatcher::Extapi::Service
"able to interact with the desktop.\n\n")
return true
end
}
status_map = {
1 => "Stopped",
2 => "Starting",
3 => "Stopping",
4 => "Running",
5 => "Continuing",
6 => "Pausing",
7 => "Paused"
}
end
services = client.extapi.service.enumerate
@ -78,14 +95,14 @@ class Console::CommandDispatcher::Extapi::Service
]
)
services.each { |s|
services.each do |s|
table << [
s[:pid],
status_map[s[:status]],
@status_map[s[:status]],
s[:interactive] ? "Y" : "N",
"#{s[:name].downcase} (#{s[:display]})"
]
}
end
print_line
print_line(table.to_s)
@ -107,9 +124,9 @@ class Console::CommandDispatcher::Extapi::Service
# Query a single service for more detail.
#
def cmd_service_query(*args)
args << "-h" if args.length == 0
args.unshift("-h") if args.length != 1
@@service_query_opts.parse(args) { |opt, idx, val|
@@service_query_opts.parse(args) do |opt, idx, val|
case opt
when "-h"
print(
@ -119,25 +136,18 @@ class Console::CommandDispatcher::Extapi::Service
"binary path, DACL, load order group, start type and more.\n\n")
return true
end
}
end
service_name = args.shift
start_type_map = {
0 => "Boot",
1 => "System",
2 => "Automatic",
3 => "Manual",
4 => "Disabled"
}
detail = client.extapi.service.query(service_name)
print_line
print_line("Name : #{service_name}")
print_line("Display : #{detail[:display]}")
print_line("Account : #{detail[:startname]}")
print_line("Start Type : #{start_type_map[detail[:starttype]]}")
print_line("Status : #{@status_map[detail[:status]]}")
print_line("Start Type : #{@start_type_map[detail[:starttype]]}")
print_line("Path : #{detail[:path]}")
print_line("L.O. Group : #{detail[:logroup]}")
print_line("Interactive : #{detail[:interactive] ? "Yes" : "No"}")
@ -146,6 +156,39 @@ class Console::CommandDispatcher::Extapi::Service
end
#
# Options for the service_control command.
#
@@service_control_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ]
)
#
# Query a single service for more detail.
#
def cmd_service_control(*args)
args.unshift("-h") if args.length != 2
@@service_control_opts.parse(args) do |opt, idx, val|
case opt
when "-h"
print(
"\nUsage: service_control [-h] <servicename> <op>\n" +
" <servicename> : The name of the service to control.\n" +
" <op> : The operation to perform on the service.\n" +
" Valid ops: start pause resume stop restart.\n\n")
return true
end
end
service_name = args[0]
op = args[1]
client.extapi.service.control(service_name, op)
print_good("Operation #{op} succeeded.")
end
end
end