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.
450 451 452 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 450 def initialize @lexer = nil end |
Instance Attribute Details
#lexer ⇒ Object (readonly)
Returns the value of attribute lexer.
448 449 450 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 448 def lexer @lexer end |
Instance Method Details
#block_ahead? ⇒ Boolean
True when the current token names a block, i.e. it's followed by {.
548 549 550 551 552 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 548 def block_ahead? return false unless name_token? nt = peek_token(1) !nt.nil? && nt.type == :symbol && nt.value == '{' end |
#current_token ⇒ Object
525 526 527 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 525 def current_token @lexer.tokens[@index] end |
#expect(types) ⇒ Object
558 559 560 561 562 563 564 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 558 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
566 567 568 569 570 571 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 566 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
554 555 556 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 554 def expect_name expect([:identifier, :keyword]) end |
#expect_symbol(symbol) ⇒ Object
573 574 575 576 577 578 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 573 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
580 581 582 583 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 580 def match_keyword(word) token = current_token token && token.type == :keyword && token.value == word end |
#match_symbol(symbol) ⇒ Object
585 586 587 588 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 585 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.
542 543 544 545 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 542 def name_token? t = current_token !t.nil? && (t.type == :identifier || t.type == :keyword) end |
#next_token ⇒ Object
533 534 535 536 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 533 def next_token @index += 1 current_token end |
#parse(file) ⇒ Object
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 454 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
510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 510 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
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 489 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
481 482 483 484 485 486 487 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 481 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
529 530 531 |
# File 'lib/msf/core/payload/malleable_c2.rb', line 529 def peek_token(offset = 1) @lexer.tokens[@index + offset] end |