Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/spec/lib/rex/post/meterpreter/packet_spec.rb
Views: 11789
# -*- coding:binary -*-1require 'rex/post/meterpreter/packet'23RSpec.describe Rex::Post::Meterpreter::Tlv do4subject(:tlv) {5Rex::Post::Meterpreter::Tlv.new(6Rex::Post::Meterpreter::TLV_TYPE_STRING,7"test"8)9}1011it "should respond to type" do12expect(tlv).to respond_to :type13end1415it "should respond to value" do16expect(tlv).to respond_to :value17end1819it "should respond to compress" do20expect(tlv).to respond_to :compress21end2223it "should respond to inspect" do24expect(tlv).to respond_to :inspect25end2627it "should respond to meta_type?" do28expect(tlv).to respond_to :meta_type?29end3031it "should respond to type?" do32expect(tlv).to respond_to :type?33end3435it "should respond to value?" do36expect(tlv).to respond_to :value?37end3839it "should respond to to_r" do40expect(tlv).to respond_to :to_r41end4243it "should respond to from_r" do44expect(tlv).to respond_to :from_r45end4647context "TLV with value mapped to a single type" do48subject(:tlv) {49Rex::Post::Meterpreter::Tlv.new(50Rex::Post::Meterpreter::TLV_TYPE_RESULT,51052)53}5455it "should have a single type" do56expect(tlv.inspect).to eq "#<Rex::Post::Meterpreter::Tlv type=RESULT meta=INT value=0>"57end58end5960context "TLV with value mapped to multiple types" do61subject(:tlv) {62Rex::Post::Meterpreter::Tlv.new(63151074, # Multiple TLV Types are defined as this value, as described here: https://github.com/rapid7/metasploit-framework/pull/16258#discussion_r81787846964065)66}6768# https://github.com/rapid7/metasploit-framework/pull/16258#discussion_r81787846969it "should handle multiple types in alphabetical order" do70expect(tlv.inspect).to eq "#<Rex::Post::Meterpreter::Tlv type=oneOf(EXT_WINDOW_ENUM_PID,PEINJECTOR_SHELLCODE_SIZE,SNIFFER_INTERFACE_ID,WEBCAM_INTERFACE_ID) meta=INT value=0>"71end72end7374context "TLV with an unknown TLV type" do75subject(:tlv) {76Rex::Post::Meterpreter::Tlv.new(77-1,78079)80}8182it "should have an unknown type" do83expect(tlv.inspect).to eq "#<Rex::Post::Meterpreter::Tlv type=unknown--1 meta=unknown-meta-type value=\"0\">"84end85end8687context "A String TLV" do88it "should return the correct TLV type" do89expect(tlv.type).to eq Rex::Post::Meterpreter::TLV_TYPE_STRING90end9192it "should return the correct value" do93expect(tlv.value).to eq "test"94end9596context "#type?" do97it "should return true for STRING" do98expect(tlv.type?(Rex::Post::Meterpreter::TLV_TYPE_STRING)).to eq true99end100101it "should return false for UINT" do102expect(tlv.type?(Rex::Post::Meterpreter::TLV_TYPE_UINT)).to eq false103end104end105106context "#value?" do107it "should return true for the correct value" do108expect(tlv.value?("test")).to eq true109end110111it "should return false for an incorrect value" do112expect(tlv.value?("fake")).to eq false113end114end115116context "#inspect" do117it "should return a string representation of the TLV" do118tlv_to_s = "#<Rex::Post::Meterpreter::Tlv type=STRING meta=STRING value=\"test\">"119expect(tlv.inspect).to eq tlv_to_s120end121end122123context "Any non group TLV_TYPE" do124subject(:tlv_types){125excludedTypes = ["TLV_TYPE_ANY", "TLV_TYPE_EXCEPTION", "TLV_TYPE_CHANNEL_DATA_GROUP", "TLV_TYPE_TRANS_GROUP"]126typeList = []127Rex::Post::Meterpreter.constants.each do |type|128typeList << type.to_s if type.to_s.include?("TLV_TYPE") && !excludedTypes.include?(type.to_s)129end130typeList131}132133it "will not raise error on inspect" do134tlv_types.each do |type|135inspectable = Rex::Post::Meterpreter::Tlv.new(136Rex::Post::Meterpreter.const_get(type),137"test"138)139expect(inspectable.inspect).to be_a_kind_of String140end141end142end143144context "#to_r" do145it "should return the raw bytes of the TLV to send over the wire" do146tlv_bytes = "\x00\x00\x00\r\x00\x01\x00\ntest\x00"147expect(tlv.to_r).to eq tlv_bytes148end149end150151context "#from_r" do152it "should adjust the tlv attributes from the given raw bytes" do153tlv.from_r("\x00\x00\x00\r\x00\x01\x00\ntes2\x00")154expect(tlv.value).to eq "tes2"155end156end157end158159context "A Command ID TLV" do160context 'when the Command ID is valid' do161subject(:tlv) {162Rex::Post::Meterpreter::Tlv.new(163Rex::Post::Meterpreter::TLV_TYPE_COMMAND_ID,1641001165)166}167it "should have a meta type of UINT" do168expect(tlv.meta_type?(Rex::Post::Meterpreter::TLV_META_TYPE_UINT)).to eq true169end170171it "should show the correct type and meta type in inspect" do172tlv_to_s = "#<Rex::Post::Meterpreter::Tlv type=COMMAND_ID meta=INT value=1001 command=stdapi_fs_chdir>"173expect(tlv.inspect).to eq tlv_to_s174end175end176177context 'when the Command ID is invalid' do178subject(:tlv) {179Rex::Post::Meterpreter::Tlv.new(180Rex::Post::Meterpreter::TLV_TYPE_COMMAND_ID,18131337182)183}184it "should have a meta type of UINT" do185expect(tlv.meta_type?(Rex::Post::Meterpreter::TLV_META_TYPE_UINT)).to eq true186end187188it "should show the correct type and meta type in inspect" do189tlv_to_s = "#<Rex::Post::Meterpreter::Tlv type=COMMAND_ID meta=INT value=31337 command=unknown>"190expect(tlv.inspect).to eq tlv_to_s191end192end193end194195context "A String TLV with a number value" do196subject(:tlv) {197Rex::Post::Meterpreter::Tlv.new(Rex::Post::Meterpreter::TLV_TYPE_STRING,5)198}199it "should return the string version of the number" do200expect(tlv.value).to eq "5"201end202end203204end205206RSpec.describe Rex::Post::Meterpreter::GroupTlv do207subject(:group_tlv) {208Rex::Post::Meterpreter::GroupTlv.new(209Rex::Post::Meterpreter::TLV_TYPE_CHANNEL_DATA_GROUP210)211}212213it "should respond to tlvs" do214expect(group_tlv).to respond_to :tlvs215end216217it "should respond to each" do218expect(group_tlv).to respond_to :each219end220221it "should respond to each_tlv" do222expect(group_tlv).to respond_to :each_tlv223end224225it "should respond to each_with_index" do226expect(group_tlv).to respond_to :each_with_index227end228229it "should respond to each_tlv_with_index" do230expect(group_tlv).to respond_to :each_tlv_with_index231end232233it "should respond to get_tlvs" do234expect(group_tlv).to respond_to :get_tlvs235end236237it "should respond to add_tlv" do238expect(group_tlv).to respond_to :add_tlv239end240241it "should respond to add_tlvs" do242expect(group_tlv).to respond_to :add_tlvs243end244245it "should respond to get_tlv" do246expect(group_tlv).to respond_to :get_tlv247end248249it "should respond to get_tlv_value" do250expect(group_tlv).to respond_to :get_tlv_value251end252253it "should respond to get_tlv_values" do254expect(group_tlv).to respond_to :get_tlv_values255end256257it "should respond to has_tlv?" do258expect(group_tlv).to respond_to :has_tlv?259end260261it "should respond to reset" do262expect(group_tlv).to respond_to :reset263end264265it "should respond to to_r" do266expect(group_tlv).to respond_to :to_r267end268269it "should respond to from_r" do270expect(group_tlv).to respond_to :from_r271end272273it "should return an empty array for tlvs by default" do274expect(group_tlv.tlvs).to eq []275end276277context "#add_tlv" do278it "should add to the tlvs array when given basic tlv parameters" do279group_tlv.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,"test")280expect(group_tlv.tlvs.first.type).to eq Rex::Post::Meterpreter::TLV_TYPE_STRING281expect(group_tlv.tlvs.first.value).to eq "test"282end283284it "should replace any existing TLV of the same type when the replace flag is set to true" do285group_tlv.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,"test")286group_tlv.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,"test2", true)287expect(group_tlv.tlvs.count).to eq 1288expect(group_tlv.tlvs.first.value).to eq "test2"289end290291it "should add both if replace is set to false" do292group_tlv.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,"test")293group_tlv.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,"test2", false)294expect(group_tlv.tlvs.first.value).to eq "test"295expect(group_tlv.tlvs.last.value).to eq "test2"296end297end298299context "#add_tlvs" do300it "should be able to add an array of type-value hashes" do301tlv_array = [302{'type' => Rex::Post::Meterpreter::TLV_TYPE_STRING, 'value' => "test"},303{'type' => Rex::Post::Meterpreter::TLV_TYPE_STRING, 'value' => "test2"}304]305group_tlv.add_tlvs(tlv_array)306expect(group_tlv.tlvs.count).to eq 2307expect(group_tlv.tlvs.first.value).to eq "test"308expect(group_tlv.tlvs.last.value).to eq "test2"309end310311it "should raise an error when given something other than nil or an array" do312skip "RM #7598"313expect(group_tlv.add_tlvs("bad value")).to raise_error314end315316it "should raise an error when given an array of objects other than hashes" do317skip "RM #7598"318expect(group_tlv.add_tlvs([1,2,3])).to raise_error319end320321it "should raise an error when any of the hashes are missing a key" do322skip "RM #7598"323tlv_array = [324{:type => Rex::Post::Meterpreter::TLV_TYPE_STRING, :value => "test"},325{:type => Rex::Post::Meterpreter::TLV_TYPE_STRING}326]327expect(group_tlv.add_tlvs(tlv_array)).to raise_error328end329end330331context "with TLVs added" do332before(:example) do333group_tlv.reset334tlv_array = [335{'type' => Rex::Post::Meterpreter::TLV_TYPE_STRING, 'value' => "test"},336{'type' => Rex::Post::Meterpreter::TLV_TYPE_STRING, 'value' => "test2"},337{'type' => Rex::Post::Meterpreter::TLV_TYPE_UINT, 'value' => 5}338]339group_tlv.add_tlvs(tlv_array)340@raw_group = "\x00\x00\x00/@\x00\x005\x00\x00\x00\r\x00\x01\x00\ntest\x00\x00\x00\x00\x0E\x00\x01\x00\ntest2\x00\x00\x00\x00\f\x00\x02\x00\v\x00\x00\x00\x05"341end342343it "should empty the array of TLV when reset is called" do344group_tlv.reset345expect(group_tlv.tlvs).to eq []346end347348it "should convert to raw bytes when to_r is called" do349expect(group_tlv.to_r).to eq @raw_group350end351352353context "#from_r" do354it "should build the TLV group when given the proper raw bytes" do355group_tlv.reset356group_tlv.from_r( @raw_group)357expect(group_tlv.tlvs[0].inspect).to eq "#<Rex::Post::Meterpreter::Tlv type=STRING meta=STRING value=\"test\">"358expect(group_tlv.tlvs[1].inspect).to eq "#<Rex::Post::Meterpreter::Tlv type=STRING meta=STRING value=\"test2\">"359expect(group_tlv.tlvs[2].inspect).to eq "#<Rex::Post::Meterpreter::Tlv type=UINT meta=INT value=5>"360end361end362363364context "#get_tlvs" do365it "should return all TLVs of the supplied type" do366tlvs = group_tlv.get_tlvs(Rex::Post::Meterpreter::TLV_TYPE_STRING)367expect(tlvs.count).to eq 2368expect(tlvs.first.value).to eq "test"369expect(tlvs.last.value).to eq "test2"370end371372it "should return all TLVs when supplied the ANY TLV type" do373tlvs = group_tlv.get_tlvs(Rex::Post::Meterpreter::TLV_TYPE_ANY)374expect(tlvs.count).to eq group_tlv.tlvs.count375end376377it "should return an empty array for a TLV type that isn't present" do378expect(group_tlv.get_tlvs(Rex::Post::Meterpreter::TLV_TYPE_BOOL)).to eq []379end380381it "should return an empty array for a nonexistent TLV type" do382expect(group_tlv.get_tlvs(55555555)).to eq []383end384end385386context "#get_tlv" do387it "should return the first TLV of the specified type by default" do388expect(group_tlv.get_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING)).to eq group_tlv.tlvs.first389expect(group_tlv.get_tlv(Rex::Post::Meterpreter::TLV_TYPE_UINT)).to eq group_tlv.tlvs.last390end391392it "should return the correct TLV of the specified type for the given index" do393expect(group_tlv.get_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,1)).to eq group_tlv.tlvs[1]394end395396it "should return nil if given an out of bounds index" do397expect(group_tlv.get_tlv(Rex::Post::Meterpreter::TLV_TYPE_STRING,5)).to eq nil398end399400it "should return nil if given a non-present TLV type" do401expect(group_tlv.get_tlv(Rex::Post::Meterpreter::TLV_TYPE_BOOL)).to eq nil402end403end404405context "#get_tlv_value" do406it "should return the value of the first TLV with the given type" do407expect(group_tlv.get_tlv_value(Rex::Post::Meterpreter::TLV_TYPE_STRING)).to eq group_tlv.tlvs.first.value408end409410it "should return the correct TLV value of the specified type for the given index" do411expect(group_tlv.get_tlv_value(Rex::Post::Meterpreter::TLV_TYPE_STRING,1)).to eq group_tlv.tlvs[1].value412end413414it "should return nil if given an out of bounds index" do415expect(group_tlv.get_tlv_value(Rex::Post::Meterpreter::TLV_TYPE_STRING,5)).to eq nil416end417418it "should return nil if given a non-present TLV type" do419expect(group_tlv.get_tlv_value(Rex::Post::Meterpreter::TLV_TYPE_BOOL)).to eq nil420end421end422423context "#get_tlv_values" do424it "should return an array of values for the designated TLV types" do425expect(group_tlv.get_tlv_values(Rex::Post::Meterpreter::TLV_TYPE_STRING)).to eq ["test", "test2"]426end427428it "should return an empty array for a non-present TLV type" do429expect(group_tlv.get_tlv_values(Rex::Post::Meterpreter::TLV_TYPE_BOOL)).to eq []430end431end432433context "#has_tlv?" do434it "should return true if the TLV Type is present" do435expect(group_tlv.has_tlv?(Rex::Post::Meterpreter::TLV_TYPE_STRING)).to eq true436end437438it "should return false if the TLV type is not present" do439expect(group_tlv.has_tlv?(Rex::Post::Meterpreter::TLV_TYPE_BOOL)).to eq false440end441end442end443end444445RSpec.describe Rex::Post::Meterpreter::Packet do446context "Request Packet" do447subject(:packet) {448Rex::Post::Meterpreter::Packet.new(449Rex::Post::Meterpreter::PACKET_TYPE_REQUEST,45031337451)452}453454it "should respond to created_at" do455expect(packet).to respond_to :created_at456end457458it "should respond to response?" do459expect(packet).to respond_to :response?460end461462it "should respond to method?" do463expect(packet).to respond_to :method?464end465466it "should respond to method" do467expect(packet).to respond_to :method468end469470it "should respond to result?" do471expect(packet).to respond_to :result?472end473474it "should respond to result=" do475expect(packet).to respond_to :result=476end477478it "should respond to result" do479expect(packet).to respond_to :result480end481482it "should respond to rid" do483expect(packet).to respond_to :rid484end485486it "should return false for response?" do487expect(packet.response?).to eq false488end489490it "should evaluate the method correctly" do491expect(packet.method?(31337)).to eq true492expect(packet.method?(0xdead)).to eq false493end494495it "should accept new methods" do496packet.method= 0xc0ffee497expect(packet.method?(0xc0ffee)).to eq true498end499500it "should return the correct method" do501expect(packet.method).to eq 31337502end503504it "should not have a result" do505expect(packet.result).to eq nil506end507508it "should return a valid request id" do509expect(packet.rid).to match /\A\d{32}\Z/510end511512it "should be created when Packet.create_request is called" do513req = Rex::Post::Meterpreter::Packet.create_request(31337)514expect(req.class).to eq Rex::Post::Meterpreter::Packet515expect(req.response?).to eq false516expect(req.method?(31337)).to eq true517end518519it "should return the correct raw byte form of the packet" do520rid = packet.rid521meth = packet.method522raw = packet.to_r523packet.add_raw(raw)524packet.from_r525expect(packet.rid).to eq rid526expect(packet.method).to eq meth527end528end529530context "a response packet" do531subject(:packet) {532Rex::Post::Meterpreter::Packet.new(533Rex::Post::Meterpreter::PACKET_TYPE_RESPONSE,53431337535)536}537before(:example) do538packet.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_RESULT, "a-ok")539end540541it "should return the correct result" do542expect(packet.result).to eq "a-ok"543end544545it "should evaluate result correctly" do546expect(packet.result?("a-ok")).to eq true547expect(packet.result?("5by5")).to eq false548end549550it "should accept a new result" do551packet.result = "test2"552expect(packet.result).to eq "test2"553end554555it "should be created when Packet.create_response is called" do556resp = Rex::Post::Meterpreter::Packet.create_response557expect(resp.class).to eq Rex::Post::Meterpreter::Packet558expect(resp.response?).to eq true559end560561end562end563564565