Class: Metasploit::Aggregator::Tlv::Packet
- Defined in:
- lib/metasploit/aggregator/tlv/packet.rb
Overview
The logical meterpreter packet class
Constant Summary collapse
- XOR_KEY_SIZE =
The Packet container itself has a custom header that is slightly different to the typical TLV packets. The header contains the following:
XOR KEY - 4 bytes Session GUID - 16 bytes Encrypt flags - 4 bytes Packet length - 4 bytes Packet type - 4 bytes Packet data - X bytes
If the encrypt flags are zero, then the Packet data is just straight TLV values as per the normal TLV packet structure.
If the encrypt flags are non-zer, then the Packet data is encrypted based on the scheme.
Flag == 1 (AES256)
IV - 16 bytes Encrypted data - X bytes
The key that is required to decrypt the data is stored alongside the session data, and hence when the packet is initially parsed, only the header is accessed. The packet itself will need to be decrypted on the fly at the point that it is required and at that point the decryption key needs to be provided.
4
- ENCRYPTED_FLAGS_SIZE =
4
- PACKET_LENGTH_SIZE =
4
- PACKET_TYPE_SIZE =
4
- PACKET_HEADER_SIZE =
XOR_KEY_SIZE + GUID_SIZE + ENCRYPTED_FLAGS_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE
- AES_IV_SIZE =
16
- ENC_FLAG_NONE =
0x0
- ENC_FLAG_AES256 =
0x1
Constants inherited from Tlv
Instance Attribute Summary collapse
-
#created_at ⇒ Object
Returns the value of attribute created_at.
-
#encrypt_flags ⇒ Object
Returns the value of attribute encrypt_flags.
-
#length ⇒ Object
Returns the value of attribute length.
-
#raw ⇒ Object
Returns the value of attribute raw.
-
#session_guid ⇒ Object
Returns the value of attribute session_guid.
Attributes inherited from GroupTlv
Attributes inherited from Tlv
Class Method Summary collapse
-
.create_request(method = nil) ⇒ Object
Creates a request with the supplied method.
-
.create_response(request = nil) ⇒ Object
Creates a response to a request if one is provided.
Instance Method Summary collapse
- #add_raw(bytes) ⇒ Object
- #aes_decrypt(key, iv, data) ⇒ Object
- #aes_encrypt(key, data) ⇒ Object
-
#decrypt_packet(key, encrypt_flags, data) ⇒ Object
Decrypt the packet based on the content of the encryption flags.
-
#from_r(key = nil) ⇒ Object
Override the function that reads from a raw byte stream so that the XORing of data is included in the process prior to passing it on to the default functionality that can parse the TLV values.
-
#initialize(type = nil, method = nil) ⇒ Packet
constructor
Initializes the packet to the supplied packet type and method, if any.
-
#method ⇒ Object
Returns the value of the packet’s method TLV.
-
#method=(method) ⇒ Object
Sets the packet’s method TLV to the method supplied.
-
#method?(method) ⇒ Boolean
Checks to see if the packet’s method is equal to the supplied method.
- #parse_header! ⇒ Object
- #raw_bytes_required ⇒ Object
-
#response? ⇒ Boolean
Checks to see if the packet is a response.
-
#result ⇒ Object
Gets the value of the packet’s result TLV.
-
#result=(result) ⇒ Object
Sets the packet’s result TLV.
-
#result?(result) ⇒ Boolean
Checks to see if the packet’s result value is equal to the supplied result.
-
#rid ⇒ Object
Gets the value of the packet’s request identifier TLV.
-
#to_r(session_guid = nil, key = nil) ⇒ Object
Override the function that creates the raw byte stream for sending so that it generates an XOR key, uses it to scramble the serialized TLV content, and then returns the key plus the scrambled data as the payload.
-
#xor_bytes(xor_key, bytes) ⇒ Object
Xor a set of bytes with a given XOR key.
Methods inherited from GroupTlv
#add_tlv, #add_tlvs, #each, #each_tlv, #each_tlv_with_index, #each_with_index, #get_tlv, #get_tlv_value, #get_tlv_values, #get_tlvs, #has_tlv?, #reset
Methods inherited from Tlv
#inspect, #meta_type?, #type?, #value?
Constructor Details
#initialize(type = nil, method = nil) ⇒ Packet
Initializes the packet to the supplied packet type and method, if any. If the packet is a request, a request identifier is created.
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 690 def initialize(type = nil, method = nil) super(type) if method self.method = method end self.created_at = ::Time.now self.raw = '' # If it's a request, generate a random request identifier if ((type == PACKET_TYPE_REQUEST) || (type == PACKET_TYPE_PLAIN_REQUEST)) rid = '' 32.times { |val| rid << rand(10).to_s } add_tlv(TLV_TYPE_REQUEST_ID, rid) end end |
Instance Attribute Details
#created_at ⇒ Object
Returns the value of attribute created_at.
592 593 594 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 592 def created_at @created_at end |
#encrypt_flags ⇒ Object
Returns the value of attribute encrypt_flags.
595 596 597 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 595 def encrypt_flags @encrypt_flags end |
#length ⇒ Object
Returns the value of attribute length.
596 597 598 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 596 def length @length end |
#raw ⇒ Object
Returns the value of attribute raw.
593 594 595 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 593 def raw @raw end |
#session_guid ⇒ Object
Returns the value of attribute session_guid.
594 595 596 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 594 def session_guid @session_guid end |
Class Method Details
.create_request(method = nil) ⇒ Object
Creates a request with the supplied method.
646 647 648 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 646 def Packet.create_request(method = nil) Packet.new(PACKET_TYPE_REQUEST, method) end |
.create_response(request = nil) ⇒ Object
Creates a response to a request if one is provided.
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 653 def Packet.create_response(request = nil) response_type = PACKET_TYPE_RESPONSE method = nil id = nil if (request) if (request.type?(PACKET_TYPE_PLAIN_REQUEST)) response_type = PACKET_TYPE_PLAIN_RESPONSE end method = request.method if request.has_tlv?(TLV_TYPE_REQUEST_ID) id = request.get_tlv_value(TLV_TYPE_REQUEST_ID) end end packet = Packet.new(response_type, method) if id packet.add_tlv(TLV_TYPE_REQUEST_ID, id) end packet end |
Instance Method Details
#add_raw(bytes) ⇒ Object
711 712 713 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 711 def add_raw(bytes) self.raw << bytes end |
#aes_decrypt(key, iv, data) ⇒ Object
746 747 748 749 750 751 752 753 754 755 756 757 758 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 746 def aes_decrypt(key, iv, data) # Create the required cipher instance aes = OpenSSL::Cipher.new('AES-256-CBC') # Generate a truly random IV # set up the encryption aes.decrypt aes.key = key aes.iv = iv # decrypt! aes.update(data) + aes.final end |
#aes_encrypt(key, data) ⇒ Object
731 732 733 734 735 736 737 738 739 740 741 742 743 744 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 731 def aes_encrypt(key, data) # Create the required cipher instance aes = OpenSSL::Cipher.new('AES-256-CBC') # Generate a truly random IV iv = aes.random_iv # set up the encryption aes.encrypt aes.key = key aes.iv = iv # encrypt and return the IV along with the result return iv, aes.update(data) + aes.final end |
#decrypt_packet(key, encrypt_flags, data) ⇒ Object
Decrypt the packet based on the content of the encryption flags.
788 789 790 791 792 793 794 795 796 797 798 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 788 def decrypt_packet(key, encrypt_flags, data) # TODO: throw an error if the expected encryption isn't the same as the given # as this could be an indication of hijacking or side-channel packet addition # as highlighted by Justin Steven on github. if key && key[:key] && key[:type] && encrypt_flags == ENC_FLAG_AES256 && encrypt_flags == key[:type] iv = data[0, AES_IV_SIZE] aes_decrypt(key[:key], iv, data[iv.length..-1]) else data end end |
#from_r(key = nil) ⇒ Object
Override the function that reads from a raw byte stream so that the XORing of data is included in the process prior to passing it on to the default functionality that can parse the TLV values.
812 813 814 815 816 817 818 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 812 def from_r(key=nil) self.parse_header! xor_key = self.raw.unpack('a4')[0] data = xor_bytes(xor_key, self.raw[PACKET_HEADER_SIZE..-1]) raw = decrypt_packet(key, self.encrypt_flags, data) super([self.length, self.type, raw].pack('NNA*')) end |
#method ⇒ Object
Returns the value of the packet’s method TLV.
868 869 870 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 868 def method return get_tlv_value(TLV_TYPE_METHOD) end |
#method=(method) ⇒ Object
Sets the packet’s method TLV to the method supplied.
861 862 863 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 861 def method=(method) add_tlv(TLV_TYPE_METHOD, method, true) end |
#method?(method) ⇒ Boolean
Checks to see if the packet’s method is equal to the supplied method.
854 855 856 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 854 def method?(method) return (get_tlv_value(TLV_TYPE_METHOD) == method) end |
#parse_header! ⇒ Object
800 801 802 803 804 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 800 def parse_header! xor_key = self.raw.unpack('a4')[0] data = xor_bytes(xor_key, self.raw[0..PACKET_HEADER_SIZE]) _, self.session_guid, self.encrypt_flags, self.length, self.type = data.unpack('a4a16NNN') end |
#raw_bytes_required ⇒ Object
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 715 def raw_bytes_required # if we have the xor bytes and length ... if self.raw.length >= PACKET_HEADER_SIZE # return a value based on the length of the data indicated by # the header xor_key = self.raw.unpack('a4')[0] decoded_bytes = xor_bytes(xor_key, raw[0, PACKET_HEADER_SIZE]) _, _, _, length, _ = decoded_bytes.unpack('a4a16NNN') length + PACKET_HEADER_SIZE - HEADER_SIZE - self.raw.length else # Otherwise ask for the remaining bytes for the metadata to get the packet length # So we can do the rest of the calculation next time PACKET_HEADER_SIZE - self.raw.length end end |
#response? ⇒ Boolean
Checks to see if the packet is a response.
840 841 842 843 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 840 def response? return ((self.type == PACKET_TYPE_RESPONSE) || (self.type == PACKET_TYPE_PLAIN_RESPONSE)) end |
#result ⇒ Object
Gets the value of the packet’s result TLV.
890 891 892 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 890 def result return get_tlv_value(TLV_TYPE_RESULT) end |
#result=(result) ⇒ Object
Sets the packet’s result TLV.
883 884 885 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 883 def result=(result) add_tlv(TLV_TYPE_RESULT, result, true) end |
#result?(result) ⇒ Boolean
Checks to see if the packet’s result value is equal to the supplied result.
876 877 878 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 876 def result?(result) return (get_tlv_value(TLV_TYPE_RESULT) == result) end |
#rid ⇒ Object
Gets the value of the packet’s request identifier TLV.
897 898 899 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 897 def rid return get_tlv_value(TLV_TYPE_REQUEST_ID) end |
#to_r(session_guid = nil, key = nil) ⇒ Object
Override the function that creates the raw byte stream for sending so that it generates an XOR key, uses it to scramble the serialized TLV content, and then returns the key plus the scrambled data as the payload.
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 766 def to_r(session_guid = nil, key = nil) xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr raw = (session_guid || NULL_GUID).dup tlv_data = GroupTlv.instance_method(:to_r).bind(self).call if key && key[:key] && key[:type] == ENC_FLAG_AES256 # encrypt the data, but not include the length and type iv, ciphertext = aes_encrypt(key[:key], tlv_data[HEADER_SIZE..-1]) # now manually add the length/type/iv/ciphertext raw << [ENC_FLAG_AES256, iv.length + ciphertext.length + HEADER_SIZE, self.type, iv, ciphertext].pack('NNNA*A*') else raw << [ENC_FLAG_NONE, tlv_data].pack('NA*') end # return the xor'd result with the key xor_key + xor_bytes(xor_key, raw) end |
#xor_bytes(xor_key, bytes) ⇒ Object
Xor a set of bytes with a given XOR key.
823 824 825 826 827 828 829 |
# File 'lib/metasploit/aggregator/tlv/packet.rb', line 823 def xor_bytes(xor_key, bytes) result = '' bytes.bytes.zip(xor_key.bytes.cycle).each do |b| result << (b[0].ord ^ b[1].ord).chr end result end |