Hack&Dev/Web
Flask 디버그 모드에서의 LFI(Local File Inclusion) 및 PIN 탈취 취약점
스우스우03
2025. 2. 22. 20:21
1. Flask 디버그 모드와 PIN 개요
- 디버그 모드는 개발자가 실시간으로 애플리케이션의 변경 사항을 반영하고, 오류가 발생했을 때 문제를 쉽게 분석할 수 있도록 돕는다.
- 디버그 모드를 활성화하면 다음과 같은 기능이 제공된다:
- 자동 리로드(Automatic Reloading)
- 소스 코드가 변경되면 서버가 자동으로 다시 실행되어 개발 속도를 높인다.
- 인터랙티브 디버거(Interactive Debugger)
- 오류가 발생하면 Werkzeug Interactive Debugger가 실행되며, 개발자가 애플리케이션 내부 상태를 분석하고 명령어를 실행할 수 있다.
- 추적 로그(Traceback Logs)
- 애플리케이션에서 발생하는 오류를 상세한 스택 트레이스(Stack Trace)와 함께 제공한다.
- 자동 리로드(Automatic Reloading)
1.1 PIN(Personal Identification Number)
- Flask 디버거는 원격 접속 보호를 위해 PIN을 사용한다.
- PIN을 입력하면 공격자가 디버거 콘솔을 통해 원격 코드 실행(RCE, Remote Code Execution)을 수행할 수 있다.
- 이 PIN은 특정 환경 변수 및 시스템 정보를 이용해 자동 생성되며, 이를 추출할 수 있으면 공격자가 디버거에 무단 접근할 수 있다.
2. LFI(Local File Inclusion)와 PIN 생성 코드 접근
- LFI 취약점이 존재하면 서버의 내부 파일을 읽어낼 수 있다.
- 이를 활용하여 PIN을 생성하는 코드를 확인하고, 실제 디버그 PIN을 계산할 수 있다.
2.1 LFI로 버전 정보 및 디버그 코드 접근
- 다음과 같은 파일들을 LFI로 읽어보면 유용한 정보를 얻을 수 있다.
- Python 버전 확인
- Flask가 사용하는 Werkzeug 버전을 확인하여 디버거 코드가 포함된 위치를 특정할 수 있다.
- <http://target.com/view?file=/usr/local/lib/python3.8/site-packages/werkzeug/__init__.py>
- Werkzeug Debug PIN 생성 코드 확인
- 이 파일을 확인하면 get_pin_and_cookie_name() 함수가 포함된 코드를 읽어낼 수 있다.
- 이 코드를 통해 PIN이 어떤 방식으로 생성되는지 분석 가능하다.
- <http://target.com/view?file=/usr/local/lib/python3.8/site-packages/werkzeug/debug/__init__.py>
3. PIN 생성 코드 분석
- Werkzeug의 get_pin_and_cookie_name() 함수는 다음과 같은 절차로 PIN을 생성한다.
3.1 PIN 생성에 사용되는 정보
- PIN은 다음과 같은 정보를 조합하여 생성된다.
3.1.1 정보
- username: getpass.getuser()
- 현재 실행 중인 유저의 이름
- modname: app.__module__ 또는 app.__class__.__module__
- Flask 애플리케이션이 정의된 모듈명
- app_name: app.__name__ 또는 app.__class__.__name__
- Flask 애플리케이션의 클래스 이름
- mod.file: sys.modules.get(modname).__file__
- Flask 모듈 파일 경로
- MAC 주소: uuid.getnode()
- 머신의 네트워크 인터페이스에서 얻은 MAC 주소
- 머신 ID: get_machine_id()
- /etc/machine-id 또는 /proc/sys/kernel/random/boot_id에서 가져옴
4. LFI를 활용한 PIN 직접 추출
- 공격자는 LFI(Local File Inclusion)를 이용하여 아래의 파일을 읽어볼 수 있다.
4.1 환경 변수에서 직접 추출 (/proc/self/environ)
<http://target.com/view?file=/proc/self/environ>
- 환경 변수 중 WERKZEUG_DEBUG_PIN이 포함되어 있을 수 있으며, 예를 들어 다음과 같은 값이 노출될 수 있다.
WERKZEUG_DEBUG_PIN=123-456-789
- 이 값을 직접 획득하면 디버거에 접근할 수 있다.
4.2 flask_debug.pickle 파일 확인
- Werkzeug는 일부 환경에서 디버그 정보를 flask_debug.pickle 파일에 저장할 수 있다.
<http://target.com/view?file=/tmp/flask_debug.pickle>
- 이 파일을 로컬에서 분석하면 PIN을 포함한 중요한 정보를 획득할 수 있다.
5. 직접 PIN을 계산하는 방법
- 만약 환경 변수에서 PIN을 직접 찾을 수 없다면, LFI를 통해 공개 정보와 비공개 정보를 획득한 후 PIN을 직접 계산할 수도 있다.
5.1 LFI로 필요한 정보 수집
- 사용자 이름(username)
- 시스템 내 사용자 계정을 확인하여 실행 중인 유저를 특정할 수 있다.
- <http://target.com/view?file=/etc/passwd>
- 애플리케이션 모듈명 및 파일 경로
- <http://target.com/view?file=/usr/local/lib/python3.8/site-packages/my_flask_app/__init__.py>
- MAC 주소
- <http://target.com/view?file=/sys/class/net/eth0/address>
- 머신 ID
- <http://target.com/view?file=/etc/machine-id>
6. 결론 및 대응 방안
6.1 공격 가능성 요약
- LFI 취약점이 존재하면 공격자는 WERKZEUG_DEBUG_PIN을 추출하거나 직접 계산 가능하다.
- PIN을 탈취하면 원격 코드 실행(RCE)이 가능하므로 매우 위험한 취약점이다.
6.2 보안 조치
- Flask 디버그 모드 비활성화 (app.debug = False)
- 환경 변수에서 WERKZEUG_DEBUG_PIN을 제거
- LFI 취약점 방어 (파일 접근 검증 및 경로 화이트리스트 적용)
- 배포 환경에서는 Flask 디버거 사용 금지