올인원 SEO 플러그인 버전 4.1.5.3에서 수정된 심각한 취약점
게시 됨: 2021-12-15All In One SEO 플러그인의 내부 감사 중에 SQL 주입 취약점과 권한 상승 버그를 발견했습니다.
악용될 경우 SQL 주입 취약점은 공격자가 영향을 받는 사이트 데이터베이스의 권한 있는 정보(예: 사용자 이름 및 해시된 암호)에 대한 액세스 권한을 부여할 수 있습니다.
우리가 발견한 권한 상승 버그는 악의적인 행위자가 액세스해서는 안 되는 보호된 REST API 엔드포인트에 대한 액세스 권한을 부여할 수 있습니다. 이를 통해 궁극적으로 구독자와 같이 권한이 낮은 계정을 가진 사용자가 영향을 받는 사이트에서 원격 코드 실행을 수행할 수 있습니다.
우리는 이메일을 통해 플러그인 작성자에게 취약점을 보고했으며 최근에 이를 해결하기 위해 버전 4.1.5.3을 출시했습니다. 최신 플러그인 버전으로 업데이트하고 Jetpack Security와 같은 보안 솔루션을 사이트에 구축하는 것이 좋습니다.
세부
플러그인 이름: 올인원 SEO
플러그인 URI: https://wordpress.org/plugins/all-in-one-seo-pack/
작성자: https://aioseo.com/
취약점
인증된 권한 에스컬레이션
영향을 받는 버전: 4.0.0과 4.1.5.2 사이의 모든 버전(포함).
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;
}
REST API 엔드포인트를 보호하기 위해 All In One SEO가 적용한 권한 검사에는 권한이 낮은 계정(예: 구독자)이 있는 사용자에게 플러그인이 등록하는 모든 단일 엔드포인트에 대한 액세스 권한을 부여할 수 있는 매우 미묘한 버그가 포함되어 있습니다.
Api::validateAccess() 메서드는 요청 중인 REST API 경로에 의존하여 주어진 요청에 적용할 권한 검사를 알고 있습니다. WordPress가 REST API 경로를 대소문자를 구분하지 않는 문자열로 취급한다는 사실을 고려하지 않았기 때문에 단일 문자를 대문자로 변경하면 권한 검사 루틴을 완전히 우회할 수 있습니다.
플러그인의 끝점 중 일부가 매우 민감하기 때문에 이것은 특히 걱정됩니다. 예를 들어, aioseo/v1/htaccess
끝점은 사이트의 .htaccess를 임의의 콘텐츠로 다시 작성할 수 있습니다. 공격자는 이 기능을 악용하여 .htaccess 백도어를 숨기고 서버에서 악성 코드를 실행할 수 있습니다.
인증된 SQL 주입
영향을 받는 버전: 4.1.3.1과 4.1.5.2 사이의 모든 버전.
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();
/wp-json/aioseo/v1/objects
REST API 경로를 통해 액세스할 수 있는 PostsTerms::searchForObjects() 메서드는 SQL 쿼리에 해당 입력을 추가하기 전에 wpdb::esc_like()를 사용하여 사용자 입력 만 이스케이프 처리했습니다. 이 방법 은 따옴표를 이스케이프하도록 설계되지 않았기 때문에 공격자는 여전히 따옴표를 삽입하고 쿼리가 사용자 자격 증명과 같은 민감한 정보를 데이터베이스에서 유출하도록 할 수 있습니다.
이 끝점은 낮은 권한의 계정을 가진 사용자가 액세스할 수 있도록 되어 있지 않지만 앞서 언급한 권한 상승 공격 벡터로 인해 이 취약점을 악용할 수 있었습니다.
타임라인
2021-12-01 – All In One SEO와 초기 접촉
2021-12-02 – 이러한 취약점에 대한 세부 정보를 보냅니다.
2021-12-08 – 올인원 SEO 4.1.5.3 출시
결론
사이트에서 사용 중인 All In One SEO 플러그인의 버전을 확인하고 영향을 받는 범위 내에 있으면 가능한 한 빨리 업데이트하는 것이 좋습니다!
Jetpack에서는 이러한 유형의 취약점으로부터 웹사이트를 보호하기 위해 열심히 노력하고 있습니다. 악성 파일 검색 및 백업을 포함하는 사이트 보안 계획을 세우는 것이 좋습니다. Jetpack Security는 사이트와 방문자의 안전을 보장하는 훌륭한 WordPress 보안 옵션입니다.
크레딧
원래 연구원: 마크 몽파스
피드백, 도움 및 수정을 위해 Jetpack Scan 팀의 나머지 팀원들에게 감사드립니다.