Poważne luki naprawione we wtyczce All In One SEO w wersji 4.1.5.3

Opublikowany: 2021-12-15

Podczas wewnętrznego audytu wtyczki All In One SEO wykryliśmy podatność na wstrzyknięcie SQL i błąd dotyczący eskalacji uprawnień.

W przypadku wykorzystania luka SQL Injection może zapewnić atakującym dostęp do uprzywilejowanych informacji z bazy danych witryny, której dotyczy luka (np. nazw użytkowników i zaszyfrowanych haseł).

Wykryty przez nas błąd eskalacji uprawnień może przyznać szkodliwym podmiotom dostęp do chronionych punktów końcowych interfejsu API REST, do których nie powinni mieć dostępu. Może to ostatecznie umożliwić użytkownikom posiadającym konta o niskich uprawnieniach, takim jak subskrybenci, zdalne wykonanie kodu w dotkniętych witrynach.

Zgłosiliśmy te luki autorowi wtyczki za pośrednictwem poczty e-mail, a oni niedawno wydali wersję 4.1.5.3, aby je usunąć. Zdecydowanie zalecamy aktualizację do najnowszej wersji wtyczki i posiadanie na swojej stronie sprawdzonego rozwiązania bezpieczeństwa, takiego jak Jetpack Security.

Detale

Nazwa wtyczki: SEO wszystko w jednym
URI wtyczki: https://wordpress.org/plugins/all-in-one-seo-pack/
Autor: https://aioseo.com/

Luki

Uwierzytelniona eskalacja uprawnień

Wersje, których dotyczy problem: Każda wersja od 4.0.0 do 4.1.5.2 włącznie.
CVE-ID: CVE-2021-25036
CVSSv3.1: 9,9
CWSS: 92,1

	/**
	 * Validates access from the routes array.
	 *
	 * @since 4.0.0
	 *
	 * @param  \WP_REST_Request $request The REST Request.
	 * @return bool                      True if validated, false if not.
	 */
	public function validateAccess( $request ) {
		$route     = str_replace( '/' . $this->namespace . '/', '', $request->get_route() );
		$routeData = isset( $this->getRoutes()[ $request->get_method() ][ $route ] ) ? $this->getRoutes()[ $request->get_method() ][ $route ] : [];

		// No direct route name, let's try the regexes.
		if ( empty( $routeData ) ) {
			foreach ( $this->getRoutes()[ $request->get_method() ] as $routeRegex => $routeInfo ) {
				$routeRegex = str_replace( '@', '\@', $routeRegex );
				if ( preg_match( "@{$routeRegex}@", $route ) ) {
					$routeData = $routeInfo;
					break;
				}
			}
		}

		if ( empty( $routeData['access'] ) ) {
			return true;
		}

		// We validate with any of the access options.
		if ( ! is_array( $routeData['access'] ) ) {
			$routeData['access'] = [ $routeData['access'] ];
		}
		foreach ( $routeData['access'] as $access ) {
			if ( current_user_can( $access ) ) {
				return true;
			}
		}

		if ( current_user_can( apply_filters( 'aioseo_manage_seo', 'aioseo_manage_seo' ) ) ) {
			return true;
		}

		return false;
	}

Kontrole uprawnień stosowane przez All In One SEO w celu zabezpieczenia punktów końcowych REST API zawierały bardzo subtelny błąd, który mógł zapewnić użytkownikom z kontami o niskich uprawnieniach (np. subskrybentom) dostęp do każdego punktu końcowego zarejestrowanego przez wtyczkę.

Metoda Api::validateAccess() opiera się na żądanej trasie interfejsu API REST, aby wiedzieć, które kontrole uprawnień należy wymusić w przypadku danego żądania. Ponieważ nie uwzględniał faktu, że WordPress traktuje trasy REST API jako ciągi bez rozróżniania wielkości liter, zmiana pojedynczego znaku na wielkie litery całkowicie ominęła procedurę sprawdzania uprawnień.

Jest to szczególnie niepokojące, ponieważ niektóre punkty końcowe wtyczki są dość wrażliwe. Na przykład punkt końcowy aioseo/v1/htaccess może przepisać plik .htaccess witryny z dowolną zawartością. Osoba atakująca może nadużywać tej funkcji, aby ukryć backdoory .htaccess i wykonać złośliwy kod na serwerze.

Uwierzytelniony wstrzyknięcie SQL

Wersje, których dotyczy problem: Każda wersja od 4.1.3.1 do 4.1.5.2 włącznie.
CVE-ID: CVE-2021-25037
CVSSv3.1: 7,7
CWSS: 80,4

/**
 * Searches for posts or terms by ID/name.
 *
 * @since 4.0.0
 *
 * @param  \WP_REST_Request  $request The REST Request
 * @return \WP_REST_Response          The response.
 */
public static function searchForObjects( $request ) {
    $body = $request->get_json_params();
 
    if ( empty( $body['query'] ) ) {
        return new \WP_REST_Response( [
            'success' => false,
            'message' => 'No search term was provided.'
        ], 400 );
    }
    if ( empty( $body['type'] ) ) {
        return new \WP_REST_Response( [
            'success' => false,
            'message' => 'No type was provided.'
        ], 400 );
    }
 
    $searchQuery = aioseo()->db->db->esc_like( $body['query'] );
 
    $objects        = [];
    $dynamicOptions = aioseo()->dynamicOptions->noConflict();
    if ( 'posts' === $body['type'] ) {
 
        $postTypes = aioseo()->helpers->getPublicPostTypes( true );
        foreach ( $postTypes as $postType ) {
            // Check if post type isn't noindexed.
            if ( $dynamicOptions->searchAppearance->postTypes->has( $postType ) && ! $dynamicOptions->searchAppearance->postTypes->$postType->show ) {
                $postTypes = aioseo()->helpers->unsetValue( $postTypes, $postType );
            }
        }
 
        $objects = aioseo()->db
            ->start( 'posts' )
            ->select( 'ID, post_type, post_title, post_name' )
            ->whereRaw( "( post_title LIKE '%{$searchQuery}%' OR post_name LIKE '%{$searchQuery}%' OR )" )
            ->whereIn( 'post_type', $postTypes )
            ->whereIn( 'post_status', [ 'publish', 'draft', 'future', 'pending' ] )
            ->orderBy( 'post_title' )
            ->limit( 10 )
            ->run()
            ->result();

Metoda PostsTerms::searchForObjects(), która jest dostępna za pośrednictwem trasy interfejsu API REST /wp-json/aioseo/v1/objects , umożliwia zmianę znaczenia danych wejściowych użytkownika za pomocą funkcji wpdb ::esc_like() przed dołączeniem tych danych wejściowych do zapytania SQL. Ponieważ ta metoda nie jest przeznaczona do unikania cudzysłowów, osoba atakująca może je wstrzyknąć i wymusić wyciek z bazy danych poufnych informacji, takich jak poświadczenia użytkownika.

Chociaż ten punkt końcowy nie miał być dostępny dla użytkowników z kontami o niskich uprawnieniach, wspomniany wcześniej wektor ataku polegający na eskalacji uprawnień umożliwił im nadużycie tej luki.

Oś czasu

2021-12-01 – Pierwszy kontakt z All In One SEO
2021-12-02 – Wysyłamy im szczegółowe informacje o tych lukach
2021-12-08 – Wydano All In One SEO 4.1.5.3

Wniosek

Zalecamy sprawdzenie, z której wersji wtyczki All In One SEO korzysta Twoja witryna, a jeśli mieści się w zakresie, którego dotyczy problem, jak najszybciej ją zaktualizuj!

W Jetpack ciężko pracujemy, aby zapewnić ochronę Twoich stron internetowych przed tego typu lukami. Zalecamy posiadanie planu bezpieczeństwa dla witryny, który obejmuje skanowanie złośliwych plików i tworzenie kopii zapasowych. Jetpack Security to świetna opcja bezpieczeństwa WordPress, która zapewnia bezpieczeństwo Twojej witrynie i odwiedzającym.

Kredyty

Autor oryginalny: Marc Montpas

Podziękowania dla reszty zespołu Jetpack Scan za opinie, pomoc i poprawki.