8

I am using WordPress v.4.1 and all the plugins and the theme are up to date.

I see in my log files too many of these...

xxx.xxx.xxx.xxx - - [02/Jan/2015:13:30:27 +0200] "POST /wp-cron.php?doing_wp_cron=1420198227.5184459686279296875000 HTTP/1.0" 200 - "-" "WordPress/217; http://www.example.com"

where xxx.xxx.xxx.xxx is the IP address of the server that the website is hosted and "http://www.example.com" is my website.

Is there a known vulnerability (exploit) affecting wp-cron.php?
Is there a way to "protect" the file?

Thank you!

3

In wp-includes/default-filters.php we can find a callback registration:

// WP Cron
if ( !defined( 'DOING_CRON' ) )
    add_action( 'init', 'wp_cron' );

If we go the function wp_cron() now, we see this:

$schedules = wp_get_schedules();
foreach ( $crons as $timestamp => $cronhooks ) {
    if ( $timestamp > $gmt_time ) break;
    foreach ( (array) $cronhooks as $hook => $args ) {
        if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
            continue;
        spawn_cron( $gmt_time );
        break 2;
    }
}

spawn_cron() sends the POST request that you are seeing in your logs:

$doing_wp_cron = sprintf( '%.22F', $gmt_time );
set_transient( 'doing_cron', $doing_wp_cron );

/**
 * Filter the cron request arguments.
 *
 * @since 3.5.0
 *
 * @param array $cron_request_array {
 *     An array of cron request URL arguments.
 *
 *     @type string $url  The cron request URL.
 *     @type int    $key  The 22 digit GMT microtime.
 *     @type array  $args {
 *         An array of cron request arguments.
 *
 *         @type int  $timeout   The request timeout in seconds. Default .01 seconds.
 *         @type bool $blocking  Whether to set blocking for the request. Default false.
 *         @type bool $sslverify Whether SSL should be verified for the request. Default false.
 *     }
 * }
 */
$cron_request = apply_filters( 'cron_request', array(
    'url'  => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
    'key'  => $doing_wp_cron,
    'args' => array(
        'timeout'   => 0.01,
        'blocking'  => false,
        /** This filter is documented in wp-includes/class-http.php */
        'sslverify' => apply_filters( 'https_local_ssl_verify', false )
    )
) );

wp_remote_post( $cron_request['url'], $cron_request['args'] );

Here you can also see where the float number is coming from: It is passed as an argument to identify the transient.

Nothing to worry about.

-1

If you want to protect the file you can restrict access to the file via your httpd.conf (global Apache config file).

# Wordpress wp-cron.php file
<Files "wp-cron.php">
  Require ip 1.2.3.4
</Files>

Replace the IP in the example with your server IP. This will still give you access to the file from the server using a command like:

wget -q -O - domain.com/wp-cron.php?doing_wp_cron

And it will return a 403 (access denied to requests from any other IP). If you use an additional rule such as below you will redirect external requests from 403 Forbidden to another page (such as homepage) which isn't really necessary.

ErrorDocument 403 https://www.domain.ca

Even better, you can use Require ip 127.0.0.1 with the above example and use the wget request: wget -q -O - 127.0.0.1/wp-cron.php?doing_wp_cron. That will use the loopback network controller and your request will not be forwarded out into the public internet and back.

  • 1
    that will block invocations from the OS cron that are usually done using wget – Mark Kaplun Jun 6 at 16:17
  • Can you point me to where wget is called in the source code. I quick search did not help me find it quickly. I found serveral refs to wget, but only in WordFence and BulletProof plugins. – jonnyjandles Jun 6 at 18:36
  • Wordpress does not use OS crons. Also, using the above rule, I was able to wget wp-cron.php using both wget localhost/wp-cron.php and wget 127.0.0.1/wp-cron.php. However, when attempting to access from the outside I the following in access_log "GET /wp-cron.php HTTP/1.1" 302 (redirection). Because I also have a ErrorDocument 403 domain.com/index.php which routes all access denied to the homepage. – jonnyjandles Jun 6 at 18:45
  • cron is http requested from wordpress core. All tutorials available on the net suggest that you use wget to trigger WP cron from the OS cron as a replacement to WP native crin triggering. In addition filtering by IP whih is lways a losing strategy is even worse in this case as when you move your site either cron will stop working and you will not know why or those lines will stop having any effect – Mark Kaplun Jun 7 at 16:20
  • Use 127.0.0.1 instead of server public IP as I mentioned in my answer then. – jonnyjandles Jun 7 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.