Hello World!

mercure·2024년 8월 30일
0

Dreamhack

목록 보기
7/18


사이트에 들어가면 Hello world가 나온다. 코드부터 살펴보자

app.py

from flask import Flask, request
import subprocess
import os

app = Flask(__name__)

@app.route("/", methods=["GET"])
def index():
    try:
        result = subprocess.run(
            args=["python3", "./hello.py"], capture_output=True, text=True
        )
        return result.stdout
    
    except:
        return "error!"
    
@app.route("/write", methods=["GET"])
def write():
    data = request.args.get('data')
    file = request.args.get('file')

    if os.path.exists(file):
        return "bad"
        
    with open(file, 'w') as f:
        f.write(data)
    
    return "good!"
    
    
app.run(host="0.0.0.0", port=8000)

hello.py

import __hello__

__hello__.main()
  • /
    hello.py 실행
  • /write?data={para}&file={para}
    data,file 파라미터를 받아서
    존재하는 파일이면 bad
    존재하지 않으면 good 이후 파일 쓰기 실행

flag는 권한이 111 이므로 플래그 파일을 실행하여 flag를 도출하는것으로 보아 rce공격 루트가 있는것 같다.

문제를 보자마자 찾은 자료는

  • python import 순서
  • if문 우회법
if os.path.exists(file):
        return "bad"

여기서 hello.py을 덮거나 import __hello__를 덮어보려고 했으나 후자는 실패하였다.

 if os.path.exists(file):
        return "bad"

이 부분에서 if문을 우회해서 hello.py파일을 상위 디렉터리에 존재하는 flag를 실행시켜 flag값을 얻어야 할 것으로 보인다.

라고 생각했으나 두 방법 모두 먹히지 않았다. 우선 python 모듈 import 순서부터 공부를 진행하였다.

python import 순서는 아래와 같다.

  1. sys.modules
  2. built-in modules
  3. sys.path
  1. sys.modules
    sys.modules는 이미 로드된 모듈을 저장해 두는 사전이다. 모듈을 import할 때, Python은 이곳에서 먼저 확인하고, 있으면 다시 로드하지 않고 기존 모듈을 재사용할 수 있다.

  2. built-in modules(내장 모듈)
    내장 모듈은 Python에 기본으로 포함되어 있어, 별도 설치 없이 바로 사용할 수 있다.
    ex) os, math

  3. sys.path
    sys.path는 Python이 모듈을 찾을 때 참조하는 경로 목록이다. 필요한 모듈을 이 리스트에서 찾을 수 있다.
    ex) pip를 통해 설치되는 모듈들

처음엔 당연히 하드 코딩된 ./hello.py파일을 끼워넣거나 __hello__.py 파일을 가로 채려고 공부를 진행하였으나 이것들은 이미 로드되거나 built-in modules이기 때문에 내가 sys.path에 적는다고 해도 가로챌 수 없었다. 따라서 다른 방법이 필요했다.

python3 -c "import sys; print(sys.path)"
[
'',
'/usr/local/lib/python310.zip',
'/usr/local/lib/python3.10',
'/usr/local/lib/python3.10/lib-dynload', '/home/dreamhack/.local/lib/python3.10/site-packages', '/usr/local/lib/python3.10/site-packages'
]

위 경로에서 '' 현재 경로인 /usr/local의 경로에는 파일을 쓸 권한이 없어서 불가능하다. 사용할 수 있는곳은

현재 디렉터리(/home/dreamhack/)와 /home/dreamhack/.local/lib/python3.10/site-packages 이다
(작성 여부를 도커로 확인하였다.)

여기서 내가 시도한 방법은 현재 디렉터리에서 python module hijacking 시도로 import Flask, request, subprocess,os 들이 존재하는데 위 파일의 main()함수에 flag를 실행하는 코드들 끼워넣었다. 하지만 실패하였다..../site-package/ 경로에도 위와 같이 hijacking 하였으나 실패하였다.

import순서가 후순위이기 때문이다.

site-package만의 특별한 방법이 있을거라고 생각하고 검색해본 결과

sitecustomize.py 파일이라는게 있었다.

sitecustomize.py 파일이란
Python 환경에 대해 사용자나 시스템 관리자가 특정한 설정이나 변경을 적용할 수 있도록 하는 스크립트로 이 파일에 작성된 코드는 Python 인터프리터가 시작될 때 자동으로 실행한다.

이게 왜 필요하냐 하면 python 실행시 자동으로 실행하기 때문에 여러 사용자에게 일관된 환경 설정을 제공하고, 시스템 관리자가 쉽게 특정 설정을 적용할 수 있도록 하며, 개발 및 운영 환경에 맞춤화된 초기화를 가능하게 한다.

이를 통해 /../site-packages/경로에 작성하여 원하는 파이썬 코드를 실행시키는 RCE 공격이 가능하다.

/write?data=import+os%0Aos.system('/flag')&file=/home/dreamhack/.local/lib/python3.10/site-packages/sitecustomize.py

따라서 위와 같은 페이로드를 보내준다면 / 경로 진입시 /flag를 출력하고 hello world가 출력될 것이다.

profile
하루에 한걸음씩

0개의 댓글

관련 채용 정보