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/lib/rex/proto/drda/packet.rb
Views: 11704
# -*- coding: binary -*-123module Rex4module Proto5module DRDA::Packet67class Error < StandardError; end8class RespError < Error; end910# See:11# http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.drda/db2z_excsat.htm12class MGRLVLLS_PARAM < Struct.new(:length, :codepoint, :payload)13def initialize(args={})14self[:codepoint] = Rex::Proto::DRDA::Constants::MGRLVLLS15self[:payload] = "\x14\x03\x00\x0a\x24\x07\x00\x0a" +16"\x14\x74\x00\x05\x24\x0f\x00\x08" +17"\x14\x40\x00\x09\x1c\x08\x04\xb8"18self[:length] = self[:payload].to_s.size+419end20def to_s21self.to_a.pack("nna*")22end23end2425# Currently, only takes a MGRLVLLS param. Extend the struct26# when more parameters are defined.27class EXCSAT_DDM < Struct.new(:length, :magic, :format, :correlid, :length2,28:codepoint, :mgrlvlls)2930def initialize(args={})31self[:magic] = 0xd032self[:format] = 0x4133self[:correlid] = 134self[:codepoint] = Rex::Proto::DRDA::Constants::EXCSAT35self[:mgrlvlls] = args[:mgrlvlls] || MGRLVLLS_PARAM.new.to_s36self[:length] = (10 + self[:mgrlvlls].to_s.size)37self[:length2] = self[:length]-638end3940def to_s41packstr = "nCCnnn"42packstr += "a*" # Pack smarter as more params are added.43self.to_a.pack(packstr)44end45end4647# See http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.drda/db2z_accsec.htm48# for all sorts of info about SECMEC.49class SECMEC_PARAM < Struct.new(:length, :codepoint, :payload)50def initialize(args={})51self[:length] = 652self[:codepoint] = Rex::Proto::DRDA::Constants::SECMEC53self[:payload] = 3 # Plaintext username and password.54end55def to_s56self.to_a.pack("nnn")57end58end5960# Relational Database name parameter.61class RDBNAM_PARAM < Struct.new(:length, :codepoint, :payload)62def initialize(args={})63self[:length] = 22 # Since the database name is padded out.64self[:codepoint] = Rex::Proto::DRDA::Constants::RDBNAM65self[:payload] = encode(args[:payload].to_s)66end6768def encode(str)69Rex::Text.to_ebcdic([str].pack("A18"))70end7172def payload=(str)73self[:payload] = encode(str.to_s)74end7576def to_s77self.to_a.pack("nna18")78end7980end8182# The ACCSEC DDM is responsible for picking the security mechanism (SECMEC)83# which, in our case, will always be plain text username and password. It84# also sets the relational database name (RDBNAM), if specified. You need85# one to login, but not to probe.86class ACCSEC_DDM < Struct.new(:length, :magic, :format, :correlid, :length2,87:codepoint, :secmec, :rdbnam)88def initialize(args={})89self[:magic] = 0xd090self[:format] = args[:format] || 0x0191self[:correlid] = 292self[:codepoint] = Rex::Proto::DRDA::Constants::ACCSEC93self[:secmec] = SECMEC_PARAM.new.to_s94if args[:dbname] # Include a database name if we're given one.95self[:rdbnam] = RDBNAM_PARAM.new(:payload => args[:dbname]).to_s96end97self[:length] = 10 + self[:secmec].to_s.size + self[:rdbnam].to_s.size98self[:length2] = self[:length]-699end100def dbname=(str)101self[:rdbnam] = RDBNAM_PARAM.new(:payload => args[:dbname]).to_s102end103def to_s104packstr = "nCCnnna6"105packstr += "a22" if self[:rdbnam]106self.to_a.pack(packstr)107end108end109110class DDM_PARAM < Struct.new(:length, :codepoint, :payload)111112def read(str="")113raise DRDA::Error, "Input isn't a String." if !str.kind_of? String114raise DRDA::RespError, "DDM_PARAM is too short" if str.size < 4115(self[:length], self[:codepoint]) =116str.unpack("nn")117raise DRDA::RespError, "DDM_PARAM Length is too short" if self[:length] < 4118rest = str[4,self[:length]-4] # If it's negative or whatever, it'll end up as "".119self[:payload] = rest.to_s[0,self[:length]-4]120return self121end122123def to_s124self.to_a.pack("nna*")125end126127end128129class BASIC_DDM < Struct.new(:length, :magic, :format, :correlid,130:length2, :codepoint, :payload)131def initialize132self[:payload] = []133end134135def read(str="")136self[:payload].clear137raise DRDA::Error, "Input isn't a String." if !str.kind_of? String138raise DRDA::RespError, "Response is too short." if str.size < 10139(self[:length],self[:magic],self[:format],140self[:correlid],self[:length2],self[:codepoint]) =141str.unpack("nCCnnn")142sanity_check143rest = str[10,self[:length2]-4]144i = 0145while (i < rest.size)146if self[:codepoint] == Rex::Proto::DRDA::Constants::SQLCARD # These aren't DDM's.147this_param = rest[i,self[:length]-10]148else149this_param = DDM_PARAM.new.read(rest[i,rest.size])150end151self[:payload] << this_param152i += this_param.to_s.size153end154return self155end156157# Just a quick test.158def sanity_check159if self[:length] < 10160raise DRDA::RespError, "DDM Length is too short."161elsif self[:length2] < 4162raise DRDA::RespError, "DDM Length2 is too short."163elsif self[:length]-6 != self[:length2]164raise DRDA::RespError, "Codepoint: 0x#{self[:codepoint].to_s(16)} DDM Length2 (0x#{self[:length2].to_s(16)}) isn't six less than Length (0x#{self[:length].to_s(16)})"165end166end167168def to_s169self.to_a.pack("nCCnnn") + self[:payload].map {|x| x.to_s}.join170end171172end173174class SERVER_PACKET < Array175176def read(str="")177raise DRDA::Error, "Input isn't a String." if !str.kind_of? String178self.clear179i = 0180while(i < str.size)181this_ddm = BASIC_DDM.new.read(str[i,str.size])182self << this_ddm183i += this_ddm.to_s.size184end185return self186end187188def to_s; self.join; end189def sz; self.to_s.size; end190191end192193class PASSWORD_PARAM < Struct.new(:length, :codepoint, :payload)194def initialize(args={})195self[:codepoint] = Rex::Proto::DRDA::Constants::PASSWORD196self[:payload] = Rex::Text.to_ebcdic(args[:payload].to_s)197self[:length] = self[:payload].size + 4198end199def encode(str)200Rex::Text.to_ebcdic(str)201end202def to_s203self.to_a.pack("nna*")204end205end206207class USERID_PARAM < Struct.new(:length, :codepoint, :payload)208def initialize(args={})209self[:codepoint] = Rex::Proto::DRDA::Constants::USERID210self[:payload] = Rex::Text.to_ebcdic(args[:payload].to_s)211self[:length] = self[:payload].size + 4212end213def encode(str)214Rex::Text.to_ebcdic(str)215end216def to_s217self.to_a.pack("nna*")218end219end220221class SECCHK_DDM < Struct.new(:length, :magic, :format, :correlid, :length2,222:codepoint, :secmec, :rdbnam, :password, :userid)223def initialize(args={}) # Takes :dbname, :dbpass, :dbuser224self[:magic] = 0xd0225self[:format] = 0x01226self[:correlid] = 2227self[:codepoint] = Rex::Proto::DRDA::Constants::SECCHK228self[:secmec] = SECMEC_PARAM.new.to_s229if args[:dbname] # Include a database name if we're given one.230self[:rdbnam] = RDBNAM_PARAM.new(:payload => args[:dbname]).to_s231end232self[:password] = PASSWORD_PARAM.new(:payload => args[:dbpass]).to_s233self[:userid] = USERID_PARAM.new(:payload => args[:dbuser]).to_s234self[:length] = ( 10 + self[:secmec].to_s.size + self[:rdbnam].to_s.size +235self[:password].to_s.size + self[:userid].to_s.size )236self[:length2] = self[:length]-6237end238def dbname=(str)239self[:rdbnam] = RDBNAM_PARAM.new(:payload => args[:dbname]).to_s240end241def to_s242packstr = "nCCnnna6"243packstr += "a22" if self[:rdbnam]244packstr += "a*a*" # username and password245self.to_a.pack(packstr)246end247end248249end250end251end252253254255