★CVE-2023-6875: Bypass de autorização no POST SMTP Mailer até tomada de conta admin
Meu achado de bypass de autorização no POST SMTP Mailer, o fluxo do proof of concept e por que o impacto era alto.
Esse foi meu primeiro grande acerto em bug bounty: CVE-2023-6875, um bypass de autorização no plugin POST SMTP Mailer para WordPress.
O proof of concept público está aqui:
Enviei o proof of concept para a Wordfence durante o Holiday Bug Bonanza. O PoC recebeu um prêmio extra, o que foi muito legal.
O bug
Este é o relatório e writeup original enviado para a Wordfence:
Visão geral: POST SMTP Mailer é vulnerável a uma vulnerabilidade de type juggling no endpoint REST API post-smtp/v1/connect-app. Essa vulnerabilidade de type juggling permite que um atacante defina o access token do site alvo. Com esse access token, um atacante pode usar qualquer endpoint REST API autenticado do post-smtp.
Descrição:
O plugin POST SMTP Mailer implementa o endpoint "connect-app", que permite que um usuário conecte seu site ao aplicativo móvel do POST SMTP. Para isso, uma auth key é gerada e fica disponível no painel de administração. Essa auth key é um transient com a chave "post_smtp_auth_nonce".
Ao comparar a chave, o plugin faz a seguinte verificação:
public function connect_app( WP_REST_Request $request ) {
$nonce = get_transient( 'post_smtp_auth_nonce' );
$auth_key = $request->get_header( 'auth_key' );
$fcm_token = $request->get_header( 'fcm_token' );
$device = $request->get_header( 'device' );
$server_url = $request->get_header( 'server_url' );
if( $auth_key == $nonce ) {
$data = array(
$fcm_token => array(
'auth_key' => $auth_key,
'fcm_token' => $fcm_token,
'device' => $device,
'enable_notification' => 1
)
);
update_option( 'post_smtp_mobile_app_connection', $data );
update_option( 'post_smtp_server_url', $server_url );
wp_send_json_success(
array(
'fcm_token' => $fcm_token
),
200
);
}
O problema está no if statement usando uma comparação fraca. Se ignorarmos o parâmetro "auth_key", a variável é avaliada como null. Se o transient ainda não estiver definido, a comparação avaliaria para o seguinte pseudo código:
[ $auth_key (null) == $nonce (false) ]=> true
A partir daí, o fcm_token seria salvo e poderíamos usá-lo em outros requests da API para autenticar com ele (mais sobre isso depois).
No entanto, podemos levar isso um passo além: se o if statement não avaliar como true, o seguinte código é executado:
delete_transient( 'post_smtp_auth_nonce' );
wp_send_json_error(
array(
'error' => 'Refresh QR Code page, and scan again.'
),
200
);
Isso permitiria efetivamente definir nosso token independentemente de existir um transient ou não, já que podemos:
- Enviar um request contendo um $auth_key inválido (removendo e invalidando qualquer transient existente)
- Enviar um request sem $auth_key (entrando no if statement e salvando nosso token no servidor alvo)
É importante notar que o token é usado para toda a autenticação com a REST API (exceto o endpoint connect-app), já que os desenvolvedores do plugin optaram por ter seu próprio sistema de api-token em vez de usar uma das opções prontas que o WordPress oferece. Por causa disso, todos os endpoints da API têm o permission_callback definido como '__return_true'.
Agora, com o fcm_token definido, podemos chamar o endpoint get-logs. Esse endpoint permite ver todos os emails que foram registrados pelo plugin, com seus respectivos ids (internos ao plugin).
Sabendo o id do email, podemos ver esse email individual em sua totalidade. Vale notar que todos os emails são registrados, incluindo emails sensíveis como emails de redefinição de senha. Isso efetivamente permite uma tomada de conta admin não autenticada (ou de qualquer conta, na verdade).
Referências
A BleepingComputer cobriu o caso em 11 de janeiro de 2024, descrevendo o POST SMTP Mailer como um plugin de entrega de email usado por 300,000 sites e reportando que mais de 150k sites WordPress estavam em risco de tomada de controle.