¿Es wp-cron.php vulnerable a ataques externos y cómo protegerlo?

29 ene 2015, 21:33:02
Vistas: 43.2K
Votos: 13

Estoy usando WordPress v.4.1 y todos los plugins y el tema están actualizados.

Veo en mis archivos de registro demasiadas entradas como estas...

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"

donde xxx.xxx.xxx.xxx es la dirección IP del servidor donde está alojado el sitio web y "http://www.example.com" es mi sitio web.

¿Existe alguna vulnerabilidad (exploit) conocida que afecte a wp-cron.php?
¿Hay alguna forma de "proteger" el archivo?

¡Gracias!

0
Todas las respuestas a la pregunta 2
0

En wp-includes/default-filters.php podemos encontrar el registro de un callback:

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

Si ahora vamos a la función wp_cron(), vemos esto:

$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() envía la petición POST que estás viendo en tus logs:

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

/**
 * Filtra los argumentos de la petición cron.
 *
 * @since 3.5.0
 *
 * @param array $cron_request_array {
 *     Un array de argumentos URL para la petición cron.
 *
 *     @type string $url  La URL de la petición cron.
 *     @type int    $key  El número GMT de 22 dígitos en microtiempo.
 *     @type array  $args {
 *         Un array de argumentos para la petición cron.
 *
 *         @type int  $timeout   El tiempo de espera de la petición en segundos. Por defecto .01 segundos.
 *         @type bool $blocking  Si se debe establecer bloqueo para la petición. Por defecto false.
 *         @type bool $sslverify Si se debe verificar SSL para la petición. Por defecto 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,
        /** Este filtro está documentado en wp-includes/class-http.php */
        'sslverify' => apply_filters( 'https_local_ssl_verify', false )
    )
) );

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

Aquí también puedes ver de dónde viene el número flotante: Se pasa como argumento para identificar el transient.

Nada de qué preocuparse.

29 ene 2015 22:24:18
6

Si deseas proteger el archivo, puedes restringir el acceso al mismo a través de tu archivo httpd.conf (archivo de configuración global de Apache).

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

Reemplaza la IP en el ejemplo con la IP de tu servidor. Esto aún te dará acceso al archivo desde el servidor usando un comando como:

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

Y devolverá un 403 (acceso denegado a solicitudes desde cualquier otra IP). Si usas una regla adicional como la siguiente, redirigirás las solicitudes externas desde 403 Forbidden a otra página (como la página de inicio), lo cual no es realmente necesario.

ErrorDocument 403 https://www.dominio.ca

Incluso mejor, puedes usar Require ip 127.0.0.1 con el ejemplo anterior y usar la solicitud wget: wget -q -O - 127.0.0.1/wp-cron.php?doing_wp_cron. Eso utilizará el controlador de red loopback y tu solicitud no se enviará a la internet pública y de vuelta.

6 jun 2019 17:56:50
Comentarios

que bloqueará las invocaciones desde el cron del sistema operativo que normalmente se realizan usando wget

Mark Kaplun Mark Kaplun
6 jun 2019 19:17:03

¿Puedes indicarme dónde se llama a wget en el código fuente? Una búsqueda rápida no me ayudó a encontrarlo rápidamente. Encontré varias referencias a wget, pero solo en los plugins WordFence y BulletProof.

I'm Root James I'm Root James
6 jun 2019 21:36:07

WordPress no usa crons del sistema operativo. Además, usando la regla anterior, pude hacer wget a wp-cron.php usando tanto wget http://localhost/wp-cron.php como wget http://127.0.0.1/wp-cron.php. Sin embargo, al intentar acceder desde el exterior, obtuve lo siguiente en access_log "GET /wp-cron.php HTTP/1.1" 302 (redirección). Esto porque también tengo un ErrorDocument 403 https://www.domain.com/index.php que redirige todos los accesos denegados a la página de inicio.

I'm Root James I'm Root James
6 jun 2019 21:45:16

cron es solicitado mediante HTTP desde el núcleo de WordPress. Todos los tutoriales disponibles en la red sugieren usar wget para activar WP cron desde el cron del sistema operativo como reemplazo al disparador nativo de WP cron. Además, filtrar por IP, que siempre es una estrategia perdedora, es aún peor en este caso porque cuando mueves tu sitio, o el cron dejará de funcionar y no sabrás por qué o esas líneas dejarán de tener efecto.

Mark Kaplun Mark Kaplun
7 jun 2019 19:20:41

Usa 127.0.0.1 en lugar de la IP pública del servidor como mencioné en mi respuesta entonces.

I'm Root James I'm Root James
7 jun 2019 22:13:05

WordPress nunca usa wget para WP-Cron y si decides configurar trabajos cron a nivel de sistema operativo, probablemente tampoco deberías usar wget. Esta respuesta es inteligente, pero no va lo suficientemente lejos... podrías restringir el acceso a wp-cron.php pero luego usar WP-CLI o /usr/bin/php para llamarlo localmente.

Jesse Nickles Jesse Nickles
15 mar 2023 12:41:47
Mostrar los 1 comentarios restantes