
CVE-2017-8291 CTF (도커 및 예제 포함)
Python에서 이미지를 처리하는 PIL(Pillow) 모듈은 내부적으로 GhostScript를 호출하기 때문에 GhostButt 취약점(CVE-2017-8291)의 영향을 받아 원격 명령 실행 취약점이 발생합니다.
PIL은 내부적으로 이미지 헤더(Magic Bytes)를 기반으로 이미지 유형을 결정합니다. EPS 파일(헤더가 %!PS)로 확인되면 PIL/EpsImagePlugin.py로 전달되어 처리됩니다.
이 모듈에서 PIL은 시스템의 gs 명령어, 즉 GhostScript를 호출하여 이미지 파일을 처리합니다:
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages,
"-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
# adjust for image origin
"-f", infile, # input file
]
# Omit the code to determine whether GhostScript is installed
try:
with open(os.devnull, 'w+b') as devnull:
subprocess.check_call(command, stdin=devnull, stdout=devnull)
im = Image.open(outfile)
비록 -dSAFER, 즉 안전 모드가 설정되어 있지만, GhostScript의 샌드박스 우회 취약점(GhostButt CVE-2017-8291)으로 인해 이 안전 모드가 우회되어 임의 명령을 실행할 수 있습니다.
또한, 현재 시점에서 최신 공식 버전인 GhostScript 9.21도 이 취약점의 영향을 받으므로, 운영 체제에 GhostScript가 설치되어 있는 한 PIL에 명령 실행 취약점이 존재한다고 말할 수 있습니다.
운영 환경:
docker-compose up -d
실행 후 http://your-ip:8000/에 접속하면 업로드 페이지가 나타납니다. 정상적인 기능은 PNG 파일을 업로드하면 백엔드에서 PIL을 호출하여 이미지를 로드하고 너비와 높이를 출력하는 것입니다. 하지만 실행 명령이 포함된 EPS 파일의 확장자를 PNG로 변경하여 업로드할 수 있습니다. 백엔드가 파일 헤더를 기반으로 이미지 유형을 결정하기 때문에 확장자 검사를 무시하기 때문입니다.
예를 들어, poc.png를 업로드하면 touch /tmp/youhavebeenpwned가 실행됩니다. POC의 명령을 리버스 명령으로 변경하면 셸을 얻을 수 있습니다.