Class: Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Extapi::Adsi

Inherits:
Object
  • Object
show all
Includes:
Extensions::Extapi, Rex::Post::Meterpreter::Ui::Console::CommandDispatcher
Defined in:
lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb

Overview

Extended API ADSI management user interface.

Constant Summary collapse

Klass =
Console::CommandDispatcher::Extapi::Adsi
DEFAULT_MAX_RESULTS =

Zero indicates “no limit”

0
DEFAULT_PAGE_SIZE =
0
@@adsi_nested_group_user_enum_opts =

Options for the adsi_nested_group_user_enum command.

Rex::Parser::Arguments.new(
  '-h' => [false, 'Help banner'],
  '-o' => [true,  'Path to output file.'],
  '-m' => [true,  'Maximum results to return.'],
  '-p' => [true,  'Result set page size.']
)
@@adsi_user_enum_opts =

Options for the adsi_user_enum command.

Rex::Parser::Arguments.new(
  '-h' => [false, 'Help banner.'],
  '-o' => [true,  'Path to output file.'],
  '-m' => [true,  'Maximum results to return.'],
  '-p' => [true,  'Result set page size.']
)
@@adsi_group_enum_opts =

Options for the adsi_group_enum command.

Rex::Parser::Arguments.new(
  '-h' => [false, 'Help banner.'],
  '-o' => [true,  'Path to output file.'],
  '-m' => [true,  'Maximum results to return.'],
  '-p' => [true,  'Result set page size.']
)
@@adsi_computer_enum_opts =

Options for the adsi_computer_enum command.

Rex::Parser::Arguments.new(
  '-h' => [false, 'Help banner.'],
  '-o' => [true,  'Path to output file.'],
  '-m' => [true,  'Maximum results to return.'],
  '-p' => [true,  'Result set page size.']
)
@@adsi_dc_enum_opts =

Options for the adsi_dc_enum command.

Rex::Parser::Arguments.new(
  '-h' => [false, 'Help banner.'],
  '-o' => [true,  'Path to output file.'],
  '-m' => [true,  'Maximum results to return.'],
  '-p' => [true,  'Result set page size.']
)
@@adsi_domain_query_opts =

Options for the adsi_domain_query command.

Rex::Parser::Arguments.new(
  '-h' => [false, 'Help banner.'],
  '-o' => [true,  'Path to output file.'],
  '-m' => [true,  'Maximum results to return.'],
  '-p' => [true,  'Result set page size.']
)

Constants included from Extensions::Extapi

Extensions::Extapi::COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_GET_DATA, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_MONITOR_DUMP, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_MONITOR_PAUSE, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_MONITOR_PURGE, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_MONITOR_RESUME, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_MONITOR_START, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_MONITOR_STOP, Extensions::Extapi::COMMAND_ID_EXTAPI_CLIPBOARD_SET_DATA, Extensions::Extapi::COMMAND_ID_EXTAPI_NTDS_PARSE, Extensions::Extapi::COMMAND_ID_EXTAPI_PAGEANT_SEND_QUERY, Extensions::Extapi::COMMAND_ID_EXTAPI_SERVICE_CONTROL, Extensions::Extapi::COMMAND_ID_EXTAPI_SERVICE_ENUM, Extensions::Extapi::COMMAND_ID_EXTAPI_SERVICE_QUERY, Extensions::Extapi::COMMAND_ID_EXTAPI_WINDOW_ENUM, Extensions::Extapi::COMMAND_ID_EXTAPI_WMI_QUERY, Extensions::Extapi::EXTENSION_ID_EXTAPI, Extensions::Extapi::TLV_TYPE_EXTENSION_EXTAPI, Extensions::Extapi::TLV_TYPE_EXTENSION_PAGEANT_BLOB_IN, Extensions::Extapi::TLV_TYPE_EXTENSION_PAGEANT_ERRORMESSAGE, Extensions::Extapi::TLV_TYPE_EXTENSION_PAGEANT_RETURNEDBLOB, Extensions::Extapi::TLV_TYPE_EXTENSION_PAGEANT_SIZE_IN, Extensions::Extapi::TLV_TYPE_EXTENSION_PAGEANT_STATUS, Extensions::Extapi::TLV_TYPE_EXT_ADSI_ARRAY, Extensions::Extapi::TLV_TYPE_EXT_ADSI_BIGNUMBER, Extensions::Extapi::TLV_TYPE_EXT_ADSI_BOOL, Extensions::Extapi::TLV_TYPE_EXT_ADSI_DN, Extensions::Extapi::TLV_TYPE_EXT_ADSI_DOMAIN, Extensions::Extapi::TLV_TYPE_EXT_ADSI_FIELD, Extensions::Extapi::TLV_TYPE_EXT_ADSI_FILTER, Extensions::Extapi::TLV_TYPE_EXT_ADSI_MAXRESULTS, Extensions::Extapi::TLV_TYPE_EXT_ADSI_NUMBER, Extensions::Extapi::TLV_TYPE_EXT_ADSI_PAGESIZE, Extensions::Extapi::TLV_TYPE_EXT_ADSI_PATH, Extensions::Extapi::TLV_TYPE_EXT_ADSI_PATH_PATH, Extensions::Extapi::TLV_TYPE_EXT_ADSI_PATH_TYPE, Extensions::Extapi::TLV_TYPE_EXT_ADSI_PATH_VOL, Extensions::Extapi::TLV_TYPE_EXT_ADSI_RAW, Extensions::Extapi::TLV_TYPE_EXT_ADSI_RESULT, Extensions::Extapi::TLV_TYPE_EXT_ADSI_STRING, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_MON_DUMP, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_MON_PURGE, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_FILES, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT, Extensions::Extapi::TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_CTRL_NAME, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_CTRL_OP, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_ENUM_GROUP, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_ENUM_NAME, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_ENUM_PID, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_ENUM_STATUS, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_DACL, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_PATH, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE, Extensions::Extapi::TLV_TYPE_EXT_SERVICE_QUERY_STATUS, Extensions::Extapi::TLV_TYPE_EXT_WINDOW_ENUM_CLASSNAME, Extensions::Extapi::TLV_TYPE_EXT_WINDOW_ENUM_GROUP, Extensions::Extapi::TLV_TYPE_EXT_WINDOW_ENUM_HANDLE, Extensions::Extapi::TLV_TYPE_EXT_WINDOW_ENUM_INCLUDEUNKNOWN, Extensions::Extapi::TLV_TYPE_EXT_WINDOW_ENUM_PID, Extensions::Extapi::TLV_TYPE_EXT_WINDOW_ENUM_TITLE, Extensions::Extapi::TLV_TYPE_EXT_WMI_DOMAIN, Extensions::Extapi::TLV_TYPE_EXT_WMI_ERROR, Extensions::Extapi::TLV_TYPE_EXT_WMI_FIELD, Extensions::Extapi::TLV_TYPE_EXT_WMI_FIELDS, Extensions::Extapi::TLV_TYPE_EXT_WMI_QUERY, Extensions::Extapi::TLV_TYPE_EXT_WMI_VALUE, Extensions::Extapi::TLV_TYPE_EXT_WMI_VALUES, Extensions::Extapi::TLV_TYPE_NTDS_PATH, Extensions::Extapi::TLV_TYPE_NTDS_TEST

Instance Attribute Summary

Attributes included from Ui::Text::DispatcherShell::CommandDispatcher

#shell, #tab_complete_items

Instance Method Summary collapse

Methods included from Rex::Post::Meterpreter::Ui::Console::CommandDispatcher

check_hash, #client, #docs_dir, #filter_commands, #initialize, #log_error, #msf_loaded?, #session, set_hash, #unknown_command

Methods included from Msf::Ui::Console::CommandDispatcher::Session

#cmd_background, #cmd_background_help, #cmd_exit, #cmd_irb, #cmd_irb_help, #cmd_irb_tabs, #cmd_pry, #cmd_pry_help, #cmd_resource, #cmd_resource_help, #cmd_resource_tabs, #cmd_sessions, #cmd_sessions_help

Methods included from Ui::Text::DispatcherShell::CommandDispatcher

#cmd_help, #cmd_help_help, #cmd_help_tabs, #deprecated_cmd, #deprecated_commands, #deprecated_help, #docs_dir, #help_to_s, included, #initialize, #print, #print_error, #print_good, #print_line, #print_status, #print_warning, #tab_complete_directory, #tab_complete_filenames, #tab_complete_generic, #tab_complete_source_address, #unknown_command, #update_prompt

Instance Method Details

#adsi_computer_enum_usageObject



188
189
190
191
192
193
194
195
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 188

def adsi_computer_enum_usage
  print_line('USAGE:')
  print_line(' adsi_computer_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
  print_line
  print_line('DESCRIPTION:')
  print_line(' Enumerate all computers on the target domain.')
  print_line(@@adsi_computer_enum_opts.usage)
end

#adsi_dc_enum_usageObject



226
227
228
229
230
231
232
233
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 226

def adsi_dc_enum_usage
  print_line('USAGE:')
  print_line(' adsi_dc_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
  print_line
  print_line('DESCRIPTION:')
  print_line(' Enumerate the domain controllers on the target domain.')
  print_line(@@adsi_dc_enum_opts.usage)
end

#adsi_domain_query_usageObject



264
265
266
267
268
269
270
271
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 264

def adsi_domain_query_usage
  print_line('USAGE:')
  print_line(' adsi_domain_query <domain> <filter> <field 1> [field 2 [field ..]] [-h] [-m maxresults] [-p pagesize] [-o file]')
  print_line
  print_line('DESCRIPTION:')
  print_line(' Enumerates the objects on the target domain, returning the set of fields that are specified.')
  print_line(@@adsi_domain_query_opts.usage)
end

#adsi_group_enum_usageObject



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 148

def adsi_group_enum_usage
  print_line('USAGE:')
  print_line(' adsi_nested_group_user_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
  print_line
  print_line('DESCRIPTION:')
  print_line(' Enumerate all groups on the target domain.')
  print_line
  print_line('EXAMPLE:')
  print_line(' The example below will list all groups on the STUFUS domain.')
  print_line('  adsi_group_enum STUFUS')
  print_line(@@adsi_group_enum_opts.usage)
end

#adsi_nested_group_user_enum_usageObject



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 66

def adsi_nested_group_user_enum_usage
  print_line('USAGE:')
  print_line(' adsi_nested_group_user_enum <domain> <Group DN> [-h] [-m maxresults] [-p pagesize] [-o file]')
  print_line
  print_line('DESCRIPTION:')
  print_line(' Enumerate the users who are members of the named group, taking nested groups into account.')
  print_line(' For example, specifying the "Domain Admins" group DN will list all users who are effectively')
  print_line(' members of the Domain Admins group, even if they are in practice members of intermediary groups.')
  print_line
  print_line('EXAMPLE:')
  print_line(' The example below will list all members of the "Domain Admins" group on the STUFUS domain:')
  print_line('  adsi_nested_group_user_enum STUFUS "CN=Domain Admins,CN=Users,DC=mwrinfosecurity,DC=com"')
  print_line(@@adsi_nested_group_user_enum_opts.usage)
end

#adsi_user_enum_usageObject



111
112
113
114
115
116
117
118
119
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 111

def adsi_user_enum_usage
  print_line('USAGE:')
  print_line(' adsi_user_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
  print_line
  print_line('DESCRIPTION:')
  print_line(' Enumerate all users on the target domain.')
  print_line(' Enumeration returns information such as the user name, SAM account name, status, comments etc')
  print_line(@@adsi_user_enum_opts.usage)
end

#cmd_adsi_computer_enum(*args) ⇒ Object

Enumerate domain computers.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 200

def cmd_adsi_computer_enum(*args)
  args.unshift('-h') if args.length == 0
  if args.include?('-h')
    adsi_computer_enum_usage
    return true
  end

  domain = args.shift
  filter = '(objectClass=computer)'
  fields = ['name', 'dnshostname', 'distinguishedname', 'operatingsystem',
            'operatingsystemversion', 'operatingsystemservicepack', 'description',
            'comment' ]
  args = [domain, filter] + fields + args
  return cmd_adsi_domain_query(*args)
end

#cmd_adsi_dc_enum(*args) ⇒ Object

Enumerate domain dcs.



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 238

def cmd_adsi_dc_enum(*args)
  args.unshift('-h') if args.length == 0
  if args.include?('-h')
    adsi_dc_enum_usage
    return true
  end

  domain = args.shift
  # This LDAP filter will pull out domain controllers
  filter = '(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))'
  fields = ['name', 'dnshostname', 'distinguishedname', 'operatingsystem',
            'operatingsystemversion', 'operatingsystemservicepack', 'description', 'comment' ]
  args = [domain, filter] + fields + args
  return cmd_adsi_domain_query(*args)
end

#cmd_adsi_domain_query(*args) ⇒ Object

Enumerate domain objects.



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 276

def cmd_adsi_domain_query(*args)
  page_size = DEFAULT_PAGE_SIZE
  max_results = DEFAULT_MAX_RESULTS

  args.unshift('-h') if args.length < 3
  output_file = nil

  @@adsi_domain_query_opts.parse(args) { |opt, idx, val|
    case opt
    when '-p'
      page_size = val.to_i
    when '-o'
      output_file = val
    when '-m'
      max_results = val.to_i
    when '-h'
      adsi_domain_query_usage
      return true
    end
  }

  # Assume that the flags are passed in at the end. Safe?
  switch_index = args.index { |a| a.start_with?('-') }
  if switch_index
    args = args.first(switch_index)
  end

  domain = args.shift
  filter = args.shift

  objects = client.extapi.adsi.domain_query(domain, filter, max_results, page_size, args)

  table = Rex::Text::Table.new(
    'Header'    => "#{domain} Objects",
    'Indent'    => 0,
    'SortIndex' => 0,
    'Columns'   => objects[:fields]
  )

  objects[:results].each do |c|
    table << to_table_row(c)
  end

  print_line
  print_line(table.to_s)
  print_line("Total objects: #{objects[:results].length}")
  print_line

  if output_file
    ::File.open(output_file, 'w') do |f|
      f.write("#{table.to_s}\n")
      f.write("\nTotal objects: #{objects[:results].length}\n")
    end
  end

  return true
end

#cmd_adsi_group_enum(*args) ⇒ Object

Enumerate domain groups.



164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 164

def cmd_adsi_group_enum(*args)
  args.unshift('-h') if args.length == 0
  if args.include?('-h')
    adsi_group_enum_usage
    return true
  end

  domain = args.shift
  filter = '(objectClass=group)'
  fields = ['name', 'distinguishedname', 'description',]
  args = [domain, filter] + fields + args
  return cmd_adsi_domain_query(*args)
end

#cmd_adsi_nested_group_user_enum(*args) ⇒ Object

Enumerate domain groups.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 84

def cmd_adsi_nested_group_user_enum(*args)
  args.unshift('-h') if args.length == 0
  if args.include?('-h') || args.length < 2
    adsi_nested_group_user_enum_usage
    return true
  end

  domain = args.shift
  groupdn = args.shift
  # This OID (canonical name = LDAP_MATCHING_RULE_IN_CHAIN) will recursively search each 'memberof' parent
  # https://support.microsoft.com/en-us/kb/275523 for more information -stufus
  filter = "(&(objectClass=user)(memberof:1.2.840.113556.1.4.1941:=#{groupdn}))"
  fields = ['samaccountname', 'name', 'distinguishedname', 'description', 'comment']
  args = [domain, filter] + fields + args
  return cmd_adsi_domain_query(*args)
end

#cmd_adsi_user_enum(*args) ⇒ Object

Enumerate domain users.



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 124

def cmd_adsi_user_enum(*args)
  args.unshift('-h') if args.length == 0
  if args.include?('-h')
    adsi_user_enum_usage
    return true
  end

  domain = args.shift
  filter = '(objectClass=user)'
  fields = ['samaccountname', 'name', 'distinguishedname', 'description', 'comment']
  args = [domain, filter] + fields + args
  return cmd_adsi_domain_query(*args)
end

#commandsObject

List of supported commands.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 29

def commands
  all = {
    'adsi_user_enum'              => 'Enumerate all users on the specified domain.',
    'adsi_group_enum'             => 'Enumerate all groups on the specified domain.',
    'adsi_nested_group_user_enum' => 'Recursively enumerate users who are effectively members of the group specified.',
    'adsi_computer_enum'          => 'Enumerate all computers on the specified domain.',
    'adsi_dc_enum'                => 'Enumerate all domain controllers on the specified domain.',
    'adsi_domain_query'           => 'Enumerate all objects on the specified domain that match a filter.'
  }
  reqs = {
    'adsi_user_enum'              => [COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY],
    'adsi_group_enum'             => [COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY],
    'adsi_nested_group_user_enum' => [COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY],
    'adsi_computer_enum'          => [COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY],
    'adsi_dc_enum'                => [COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY],
    'adsi_domain_query'           => [COMMAND_ID_EXTAPI_ADSI_DOMAIN_QUERY],
  }
  filter_commands(all, reqs)
end

#nameObject

Name for this dispatcher



52
53
54
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 52

def name
  'Extapi: ADSI Management'
end

#to_table_row(result) ⇒ Array[String] (protected)

Convert an ADSI result row to a table row so that it can

be rendered to screen appropriately.

Parameters:

  • result (Array[Hash])

    Array of type/value pairs.

Returns:

  • (Array[String])

    Renderable view of the value.



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb', line 344

def to_table_row(result)
  values = []

  result.each do |v|
    case v[:type]
    when :string, :number, :bool
      values << v[:value].to_s
    when :raw
      # for UI level stuff, rendering raw as hex is really the only option
      values << Rex::Text.to_hex(v[:value], '')
    when :array
      val = "#{to_table_row(v[:value]).join(', ')}"

      # we'll truncate the output of the array because it could be excessive if we
      # don't. Users who want the detail of this stuff should probably script it.
      if val.length > 50
        val = "<#{val[0,50]}..."
      end

      values << val
    when :dn
      values << "#{value[:label]}: #{value[:string] || Rex::Text.to_hex(value[:raw], '')}"
    when :path
      values << "Vol: #{v[:volume]}, Path: #{v[:path]}, Type: #{v[:vol_type]}"
    when :unknown
      values << '(unknown)'
    end
  end

  values
end