Class: Msf::Payload::MalleableC2::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/msf/core/payload/malleable_c2.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



445
446
447
# File 'lib/msf/core/payload/malleable_c2.rb', line 445

def initialize
  @lexer = nil
end

Instance Attribute Details

#lexerObject (readonly)

Returns the value of attribute lexer.



443
444
445
# File 'lib/msf/core/payload/malleable_c2.rb', line 443

def lexer
  @lexer
end

Instance Method Details

#block_ahead?Boolean

True when the current token names a block, i.e. it’s followed by ‘{`.

Returns:

  • (Boolean)


543
544
545
546
547
# File 'lib/msf/core/payload/malleable_c2.rb', line 543

def block_ahead?
  return false unless name_token?
  nt = peek_token(1)
  !nt.nil? && nt.type == :symbol && nt.value == '{'
end

#current_tokenObject



520
521
522
# File 'lib/msf/core/payload/malleable_c2.rb', line 520

def current_token
  @lexer.tokens[@index]
end

#expect(types) ⇒ Object



553
554
555
556
557
558
559
# File 'lib/msf/core/payload/malleable_c2.rb', line 553

def expect(types)
  token = current_token
  types = [types] unless types.kind_of?(Array)
  raise "Expected #{types.inspect}, got #{token&.type}=#{token&.value}" unless token && types.include?(token.type)
  next_token
  token
end

#expect_keyword(word) ⇒ Object



561
562
563
564
565
566
# File 'lib/msf/core/payload/malleable_c2.rb', line 561

def expect_keyword(word)
  token = current_token
  raise "Expected keyword '#{word}', got #{token&.value}" unless token && token.type == :keyword && token.value == word
  next_token
  token
end

#expect_nameObject



549
550
551
# File 'lib/msf/core/payload/malleable_c2.rb', line 549

def expect_name
  expect([:identifier, :keyword])
end

#expect_symbol(symbol) ⇒ Object



568
569
570
571
572
573
# File 'lib/msf/core/payload/malleable_c2.rb', line 568

def expect_symbol(symbol)
  token = current_token
  raise "Expected symbol '#{symbol}', got #{token&.value}" unless token && token.type == :symbol && token.value == symbol
  next_token
  token
end

#match_keyword(word) ⇒ Object



575
576
577
578
# File 'lib/msf/core/payload/malleable_c2.rb', line 575

def match_keyword(word)
  token = current_token
  token && token.type == :keyword && token.value == word
end

#match_symbol(symbol) ⇒ Object



580
581
582
583
# File 'lib/msf/core/payload/malleable_c2.rb', line 580

def match_symbol(symbol)
  token = current_token
  token && token.type == :symbol && token.value == symbol
end

#name_token?Boolean

A bare name that can head a block, directive or set key. Block detection no longer depends on a keyword whitelist, so profiles can carry CS blocks we don’t model (dns-beacon, process-inject, …) without breaking the parse.

Returns:

  • (Boolean)


537
538
539
540
# File 'lib/msf/core/payload/malleable_c2.rb', line 537

def name_token?
  t = current_token
  !t.nil? && (t.type == :identifier || t.type == :keyword)
end

#next_tokenObject



528
529
530
531
# File 'lib/msf/core/payload/malleable_c2.rb', line 528

def next_token
  @index += 1
  current_token
end

#parse(file) ⇒ Object



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/msf/core/payload/malleable_c2.rb', line 449

def parse(file)
  @lexer = Lexer.new(file)
  @index = 0
  profile = ParsedProfile.new

  while current_token
    if match_keyword('set')
      profile.sets << parse_set
    elsif block_ahead?
      # Any `name { ... }` is a block. We keep the ones we understand
      # (http-get/http-post/etc.) and harmlessly retain the rest --
      # unsupported CS blocks like dns-beacon/process-inject/post-ex
      # are parsed for structure and simply ignored by to_tlv.
      profile.sections << parse_section
    elsif name_token?
      # A stray top-level directive we don't model. Consume it (up to
      # its `;`) and move on rather than failing the whole profile.
      parse_directive
    else
      raise "Unexpected token at top level: #{current_token.type}=#{current_token.value}"
    end
  end

  #@lexer = nil
  profile
end

#parse_directiveObject



505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/msf/core/payload/malleable_c2.rb', line 505

def parse_directive
  type = expect_name.value
  args = []
  while current_token && !match_symbol(';')
    if [:string, :identifier, :keyword].include?(current_token.type)
      args << current_token.value
      next_token
    else
      break
    end
  end
  expect_symbol(';')
  ParsedDirective.new(type, args)
end

#parse_sectionObject



484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
# File 'lib/msf/core/payload/malleable_c2.rb', line 484

def parse_section
  name = expect_name.value
  expect_symbol('{')
  section = ParsedSection.new(name)

  while !match_symbol('}') && current_token
    if match_keyword('set')
      section.entries << parse_set
    elsif block_ahead?
      section.sections << parse_section
    elsif name_token?
      section.entries << parse_directive
    else
      raise "Unexpected content in block #{name}: #{current_token.value}"
    end
  end

  expect_symbol('}')
  section
end

#parse_setObject



476
477
478
479
480
481
482
# File 'lib/msf/core/payload/malleable_c2.rb', line 476

def parse_set
  expect_keyword('set')
  key = expect([:identifier, :keyword]).value
  value = expect(:string).value
  expect_symbol(';')
  ParsedSet.new(key, value)
end

#peek_token(offset = 1) ⇒ Object



524
525
526
# File 'lib/msf/core/payload/malleable_c2.rb', line 524

def peek_token(offset = 1)
  @lexer.tokens[@index + offset]
end