Class: Msf::Payload::MalleableC2::Parser
- Inherits:
-
Object
- Object
- Msf::Payload::MalleableC2::Parser
- Defined in:
- lib/msf/core/payload/malleable_c2.rb
Instance Attribute Summary collapse
-
#lexer ⇒ Object
readonly
Returns the value of attribute lexer.
Instance Method Summary collapse
-
#block_ahead? ⇒ Boolean
True when the current token names a block, i.e.
- #current_token ⇒ Object
- #expect(types) ⇒ Object
- #expect_keyword(word) ⇒ Object
- #expect_name ⇒ Object
- #expect_symbol(symbol) ⇒ Object
-
#initialize ⇒ Parser
constructor
A new instance of Parser.
- #match_keyword(word) ⇒ Object
- #match_symbol(symbol) ⇒ Object
-
#name_token? ⇒ Boolean
A bare name that can head a block, directive or set key.
- #next_token ⇒ Object
- #parse(file) ⇒ Object
- #parse_directive ⇒ Object
- #parse_section ⇒ Object
- #parse_set ⇒ Object
- #peek_token(offset = 1) ⇒ Object
Constructor Details
#initialize ⇒ Parser
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
#lexer ⇒ Object (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 ‘{`.
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_token ⇒ Object
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_name ⇒ Object
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.
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_token ⇒ Object
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_directive ⇒ Object
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_section ⇒ Object
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_set ⇒ Object
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 |